diff --git a/src/fastlock.cpp b/src/fastlock.cpp index f265f3908..1a8d51165 100644 --- a/src/fastlock.cpp +++ b/src/fastlock.cpp @@ -43,6 +43,13 @@ ****************************************************/ static_assert(sizeof(pid_t) <= sizeof(fastlock::m_pidOwner), "fastlock::m_pidOwner not large enough"); +uint64_t g_longwaits = 0; + +uint64_t fastlock_getlongwaitcount() +{ + return g_longwaits; +} + extern "C" pid_t gettid() { @@ -75,7 +82,10 @@ extern "C" void fastlock_lock(struct fastlock *lock) while (__atomic_load_2(&lock->m_ticket.m_active, __ATOMIC_ACQUIRE) != myticket) { if ((++cloops % 1024*1024) == 0) + { sched_yield(); + ++g_longwaits; + } #if defined(__i386__) || defined(__amd64__) __asm__ ("pause"); #endif diff --git a/src/fastlock.h b/src/fastlock.h index b5a70c530..b8027de54 100644 --- a/src/fastlock.h +++ b/src/fastlock.h @@ -13,6 +13,8 @@ int fastlock_trylock(struct fastlock *lock); void fastlock_unlock(struct fastlock *lock); void fastlock_free(struct fastlock *lock); +uint64_t fastlock_getlongwaitcount(); // this is a global value + /* End C API */ #ifdef __cplusplus } diff --git a/src/fastlock_x64.asm b/src/fastlock_x64.asm index 1b876350f..7645d3baa 100644 --- a/src/fastlock_x64.asm +++ b/src/fastlock_x64.asm @@ -2,6 +2,7 @@ section .text extern gettid extern sched_yield +extern g_longwaits ; This is the first use of assembly in this codebase, a valid question is WHY? ; The spinlock we implement here is performance critical, and simply put GCC @@ -49,6 +50,8 @@ ALIGN 16 syscall ; give up our timeslice we'll be here a while pop rax pop rsi + mov rcx, g_longwaits + inc qword [rcx] ; increment our long wait counter mov rdi, [rsp] ; our struct pointer is on the stack already xor ecx, ecx ; Reset our loop counter jmp .LLoop ; Get back in the game diff --git a/src/networking.cpp b/src/networking.cpp index 4a6794d98..b4f14f238 100644 --- a/src/networking.cpp +++ b/src/networking.cpp @@ -138,6 +138,7 @@ void linkClient(client *c) { * this way removing the client in unlinkClient() will not require * a linear scan, but just a constant time operation. */ c->client_list_node = listLast(server.clients); + if (c->fd != -1) atomicIncr(server.rgthreadvar[c->iel].cclients, 1); uint64_t id = htonu64(c->id); raxInsert(server.clients_index,(unsigned char*)&id,sizeof(id),c,NULL); } @@ -1208,6 +1209,8 @@ void unlinkClient(client *c) { aeDeleteFileEvent(server.rgthreadvar[c->iel].el,c->fd,AE_WRITABLE); close(c->fd); c->fd = -1; + + atomicDecr(server.rgthreadvar[c->iel].cclients, 1); } /* Remove from the list of pending writes if needed. */ diff --git a/src/server.cpp b/src/server.cpp index 8707b07f5..72a589c73 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -2815,6 +2815,7 @@ static void initServerThread(struct redisServerThreadVars *pvar, int fMain) pvar->unblocked_clients = listCreate(); pvar->clients_pending_asyncwrite = listCreate(); pvar->ipfd_count = 0; + pvar->cclients = 0; pvar->el = aeCreateEventLoop(server.maxclients+CONFIG_FDSET_INCR); if (pvar->el == NULL) { serverLog(LL_WARNING, @@ -3997,6 +3998,12 @@ extern "C" sds genRedisInfoString(const char *section) { listLength(server.clients)-listLength(server.slaves), maxin, maxout, server.blocked_clients); + for (int ithread = 0; ithread < server.cthreads; ++ithread) + { + info = sdscatprintf(info, + "thread_%d_clients:%d\r\n", + ithread, server.rgthreadvar[ithread].cclients); + } } /* Memory */ @@ -4401,11 +4408,15 @@ extern "C" sds genRedisInfoString(const char *section) { "used_cpu_sys:%ld.%06ld\r\n" "used_cpu_user:%ld.%06ld\r\n" "used_cpu_sys_children:%ld.%06ld\r\n" - "used_cpu_user_children:%ld.%06ld\r\n", + "used_cpu_user_children:%ld.%06ld\r\n" + "server_threads:%d\r\n" + "long_lock_waits:%" PRIu64 "\r\n", (long)self_ru.ru_stime.tv_sec, (long)self_ru.ru_stime.tv_usec, (long)self_ru.ru_utime.tv_sec, (long)self_ru.ru_utime.tv_usec, (long)c_ru.ru_stime.tv_sec, (long)c_ru.ru_stime.tv_usec, - (long)c_ru.ru_utime.tv_sec, (long)c_ru.ru_utime.tv_usec); + (long)c_ru.ru_utime.tv_sec, (long)c_ru.ru_utime.tv_usec, + server.cthreads, + fastlock_getlongwaitcount()); } /* Command statistics */ diff --git a/src/server.h b/src/server.h index 3fa5f90a3..3417d9696 100644 --- a/src/server.h +++ b/src/server.h @@ -1053,6 +1053,7 @@ struct redisServerThreadVars { list *clients_pending_write; /* There is to write or install handler. */ list *unblocked_clients; /* list of clients to unblock before next loop NOT THREADSAFE */ list *clients_pending_asyncwrite; + int cclients; struct fastlock lockPendingWrite; };