--HG-- rename : api/leveldb/util/perf_count.cc => api/leveldb/basho/perf_count.cc rename : api/leveldb/include/leveldb/perf_count.h => api/leveldb/basho/perf_count.h rename : api/leveldb/include/leveldb/replay_iterator.h => api/leveldb/hyperleveldb/replay_iterator.h rename : api/leveldb/AUTHORS => api/leveldb/leveldb/AUTHORS rename : api/leveldb/LICENSE => api/leveldb/leveldb/LICENSE rename : api/leveldb/db/dbformat.h => api/leveldb/leveldb/db/dbformat.h rename : api/leveldb/db/skiplist.h => api/leveldb/leveldb/db/skiplist.h rename : api/leveldb/db/write_batch.cc => api/leveldb/leveldb/db/write_batch.cc rename : api/leveldb/db/write_batch_internal.h => api/leveldb/leveldb/db/write_batch_internal.h rename : api/leveldb/include/leveldb/cache.h => api/leveldb/leveldb/include/leveldb/cache.h rename : api/leveldb/include/leveldb/comparator.h => api/leveldb/leveldb/include/leveldb/comparator.h rename : api/leveldb/include/leveldb/db.h => api/leveldb/leveldb/include/leveldb/db.h rename : api/leveldb/include/leveldb/env.h => api/leveldb/leveldb/include/leveldb/env.h rename : api/leveldb/include/leveldb/filter_policy.h => api/leveldb/leveldb/include/leveldb/filter_policy.h rename : api/leveldb/include/leveldb/iterator.h => api/leveldb/leveldb/include/leveldb/iterator.h rename : api/leveldb/include/leveldb/options.h => api/leveldb/leveldb/include/leveldb/options.h rename : api/leveldb/include/leveldb/slice.h => api/leveldb/leveldb/include/leveldb/slice.h rename : api/leveldb/include/leveldb/status.h => api/leveldb/leveldb/include/leveldb/status.h rename : api/leveldb/include/leveldb/write_batch.h => api/leveldb/leveldb/include/leveldb/write_batch.h rename : api/leveldb/port/port.h => api/leveldb/leveldb/port/port.h rename : api/leveldb/util/arena.h => api/leveldb/leveldb/util/arena.h rename : api/leveldb/util/coding.cc => api/leveldb/leveldb/util/coding.cc rename : api/leveldb/util/coding.h => api/leveldb/leveldb/util/coding.h rename : api/leveldb/util/comparator.cc => api/leveldb/leveldb/util/comparator.cc rename : api/leveldb/util/env.cc => api/leveldb/leveldb/util/env.cc rename : api/leveldb/util/env_posix.cc => api/leveldb/leveldb/util/env_posix.cc rename : api/leveldb/util/logging.cc => api/leveldb/leveldb/util/logging.cc rename : api/leveldb/util/logging.h => api/leveldb/leveldb/util/logging.h rename : api/leveldb/util/options.cc => api/leveldb/leveldb/util/options.cc rename : api/leveldb/util/posix_logger.h => api/leveldb/leveldb/util/posix_logger.h rename : api/leveldb/util/random.h => api/leveldb/leveldb/util/random.h rename : api/leveldb/util/status.cc => api/leveldb/leveldb/util/status.cc
658 lines
15 KiB
C++
658 lines
15 KiB
C++
// -------------------------------------------------------------------
|
|
//
|
|
// perf_count.cc: performance counters LevelDB
|
|
//
|
|
// Copyright (c) 2012-2013 Basho Technologies, Inc. All Rights Reserved.
|
|
//
|
|
// This file is provided to you under the Apache License,
|
|
// Version 2.0 (the "License"); you may not use this file
|
|
// except in compliance with the License. You may obtain
|
|
// a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing,
|
|
// software distributed under the License is distributed on an
|
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
// KIND, either express or implied. See the License for the
|
|
// specific language governing permissions and limitations
|
|
// under the License.
|
|
//
|
|
// -------------------------------------------------------------------
|
|
|
|
#include <limits.h>
|
|
#include <stdio.h>
|
|
#include <sys/ipc.h>
|
|
#include <sys/shm.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <syslog.h>
|
|
#include <memory.h>
|
|
#include <errno.h>
|
|
|
|
#ifndef STORAGE_LEVELDB_INCLUDE_PERF_COUNT_H_
|
|
#include "perf_count.h"
|
|
#endif
|
|
|
|
#include "util/coding.h"
|
|
|
|
#define __STDC_FORMAT_MACROS
|
|
#include <inttypes.h>
|
|
|
|
#ifdef OS_SOLARIS
|
|
# include <atomic.h>
|
|
#endif
|
|
|
|
|
|
namespace leveldb
|
|
{
|
|
|
|
// always have something active in gPerfCounters, eliminates
|
|
// need to test for "is shared object attached yet"
|
|
static PerformanceCounters LocalStartupCounters;
|
|
PerformanceCounters * gPerfCounters(&LocalStartupCounters);
|
|
|
|
|
|
SstCounters::SstCounters()
|
|
: m_IsReadOnly(false),
|
|
m_Version(eSstCountVersion),
|
|
m_CounterSize(eSstCountEnumSize)
|
|
{
|
|
memset(m_Counter, 0, sizeof(m_Counter));
|
|
|
|
m_Counter[eSstCountKeySmallest]=ULLONG_MAX;
|
|
m_Counter[eSstCountValueSmallest]=ULLONG_MAX;
|
|
|
|
return;
|
|
|
|
}; // SstCounters::SstCounters
|
|
|
|
|
|
void
|
|
SstCounters::EncodeTo(
|
|
std::string & Dst) const
|
|
{
|
|
unsigned loop;
|
|
|
|
PutVarint32(&Dst, m_Version);
|
|
PutVarint32(&Dst, m_CounterSize);
|
|
|
|
for(loop=0; loop<eSstCountEnumSize; ++loop)
|
|
PutVarint64(&Dst, m_Counter[loop]);
|
|
} // SstCounters::EncodeTo
|
|
|
|
|
|
Status
|
|
SstCounters::DecodeFrom(
|
|
const Slice& src)
|
|
{
|
|
Status ret_status;
|
|
Slice cursor;
|
|
bool good;
|
|
int loop;
|
|
|
|
cursor=src;
|
|
m_IsReadOnly=true;
|
|
good=GetVarint32(&cursor, &m_Version);
|
|
good=good && (m_Version<=eSstCountVersion);
|
|
|
|
// all lesser number of stats to be read
|
|
good=good && GetVarint32(&cursor, &m_CounterSize);
|
|
if (good && eSstCountEnumSize < m_CounterSize)
|
|
m_CounterSize=eSstCountEnumSize;
|
|
|
|
for (loop=0; good && loop<eSstCountEnumSize; ++loop)
|
|
{
|
|
good=GetVarint64(&cursor, &m_Counter[loop]);
|
|
} // for
|
|
|
|
// if (!good) change ret_status to bad
|
|
|
|
return(ret_status);
|
|
|
|
} // SstCounters::DecodeFrom
|
|
|
|
|
|
uint64_t
|
|
SstCounters::Inc(
|
|
unsigned Index)
|
|
{
|
|
uint64_t ret_val;
|
|
|
|
ret_val=0;
|
|
if (!m_IsReadOnly && Index<m_CounterSize)
|
|
{
|
|
++m_Counter[Index];
|
|
ret_val=m_Counter[Index];
|
|
} // if
|
|
|
|
return(ret_val);
|
|
} // SstCounters::Inc
|
|
|
|
|
|
uint64_t
|
|
SstCounters::Add(
|
|
unsigned Index,
|
|
uint64_t Amount)
|
|
{
|
|
uint64_t ret_val;
|
|
|
|
ret_val=0;
|
|
if (!m_IsReadOnly && Index<m_CounterSize)
|
|
{
|
|
m_Counter[Index]+=Amount;
|
|
ret_val=m_Counter[Index];
|
|
} // if
|
|
|
|
return(ret_val);
|
|
} // SstCounters::Add
|
|
|
|
|
|
uint64_t
|
|
SstCounters::Value(
|
|
unsigned Index) const
|
|
{
|
|
uint64_t ret_val;
|
|
|
|
ret_val=0;
|
|
if (Index<m_CounterSize)
|
|
{
|
|
ret_val=m_Counter[Index];
|
|
} // if
|
|
|
|
return(ret_val);
|
|
} // SstCounters::Value
|
|
|
|
|
|
void
|
|
SstCounters::Set(
|
|
unsigned Index,
|
|
uint64_t Value)
|
|
{
|
|
if (Index<m_CounterSize)
|
|
{
|
|
m_Counter[Index]=Value;
|
|
} // if
|
|
|
|
return;
|
|
} // SstCounters::Set
|
|
|
|
|
|
void
|
|
SstCounters::Dump() const
|
|
{
|
|
unsigned loop;
|
|
|
|
printf("SstCounters:\n");
|
|
printf(" m_IsReadOnly: %u\n", m_IsReadOnly);
|
|
printf(" m_Version: %u\n", m_Version);
|
|
printf(" m_CounterSize: %u\n", m_CounterSize);
|
|
for (loop=0; loop<m_CounterSize; ++loop)
|
|
printf(" Counter[%2u]: %" PRIu64 "\n", loop, m_Counter[loop]);
|
|
|
|
return;
|
|
|
|
} // SstCounters::Dump
|
|
|
|
|
|
// only used for local static objects, not shared memory objects
|
|
PerformanceCounters::PerformanceCounters()
|
|
{
|
|
m_Version=ePerfVersion;
|
|
m_CounterSize=ePerfCountEnumSize;
|
|
// cast away "volatile"
|
|
memset((void*)m_Counter, 0, sizeof(m_Counter));
|
|
|
|
return;
|
|
|
|
} // PerformanceCounters::PerformanceCounters
|
|
|
|
|
|
PerformanceCounters *
|
|
PerformanceCounters::Init(
|
|
bool IsReadOnly)
|
|
{
|
|
PerformanceCounters * ret_ptr;
|
|
bool should_create, good;
|
|
int ret_val, id;
|
|
struct shmid_ds shm_info;
|
|
size_t open_size;
|
|
|
|
ret_ptr=NULL;
|
|
memset(&shm_info, 0, sizeof(shm_info));
|
|
good=true;
|
|
open_size=sizeof(PerformanceCounters);
|
|
|
|
// first id attempt, minimal request
|
|
id=shmget(ePerfKey, 0, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
|
if (-1!=id)
|
|
ret_val=shmctl(id, IPC_STAT, &shm_info);
|
|
else
|
|
ret_val=-1;
|
|
|
|
// does the shared memory already exists (and of proper size if writing)
|
|
should_create=(0!=ret_val || (shm_info.shm_segsz < sizeof(PerformanceCounters))) && !IsReadOnly;
|
|
|
|
// should old shared memory be deleted?
|
|
if (should_create && 0==ret_val)
|
|
{
|
|
ret_val=shmctl(id, IPC_RMID, &shm_info);
|
|
good=(0==ret_val);
|
|
if (0!=ret_val)
|
|
syslog(LOG_ERR, "shmctl IPC_RMID failed [%d, %m]", errno);
|
|
} // if
|
|
|
|
// else open the size that exists
|
|
else if (0==ret_val)
|
|
{
|
|
open_size=shm_info.shm_segsz;
|
|
} // else if
|
|
|
|
// attempt to attach/create to shared memory instance
|
|
if (good)
|
|
{
|
|
int flags;
|
|
|
|
if (IsReadOnly)
|
|
flags = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
|
|
else
|
|
flags = IPC_CREAT | S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
|
|
|
|
m_PerfSharedId=shmget(ePerfKey, open_size, flags);
|
|
good=(-1!=m_PerfSharedId);
|
|
} // if
|
|
|
|
// map shared memory instance
|
|
if (good)
|
|
{
|
|
ret_ptr=(PerformanceCounters *)shmat(m_PerfSharedId, NULL, (IsReadOnly ? SHM_RDONLY : 0));
|
|
if ((void*)-1 != ret_ptr)
|
|
{
|
|
// initialize?
|
|
if (should_create || ePerfVersion!=ret_ptr->m_Version)
|
|
{
|
|
if (!IsReadOnly)
|
|
{
|
|
memset(ret_ptr, 0, sizeof(PerformanceCounters));
|
|
ret_ptr->m_Version=ePerfVersion;
|
|
ret_ptr->m_CounterSize=ePerfCountEnumSize;
|
|
} // if
|
|
|
|
// bad version match to existing segment
|
|
else
|
|
{
|
|
good=false;
|
|
errno=EINVAL;
|
|
} // else
|
|
} // if
|
|
} // if
|
|
else
|
|
{
|
|
good=false;
|
|
syslog(LOG_ERR, "shmat failed [%d, %m]", errno);
|
|
} // else
|
|
|
|
if (good)
|
|
{
|
|
// make this available process wide
|
|
gPerfCounters=ret_ptr;
|
|
} // if
|
|
else
|
|
{
|
|
ret_ptr=NULL;
|
|
m_LastError=errno;
|
|
} // else
|
|
} // if
|
|
else
|
|
{
|
|
m_LastError=errno;
|
|
ret_ptr=NULL;
|
|
} // else
|
|
|
|
return(ret_ptr);
|
|
|
|
}; // PerformanceCounters::Init
|
|
|
|
|
|
int
|
|
PerformanceCounters::Close(
|
|
PerformanceCounters * Counts)
|
|
{
|
|
int ret_val;
|
|
|
|
if (NULL!=Counts && &LocalStartupCounters != Counts)
|
|
{
|
|
// keep gPerf valid
|
|
if (gPerfCounters==Counts)
|
|
gPerfCounters=&LocalStartupCounters;
|
|
|
|
ret_val=shmdt(Counts);
|
|
if (0!=ret_val)
|
|
ret_val=errno;
|
|
} // if
|
|
else
|
|
{
|
|
ret_val=EINVAL;
|
|
} // else
|
|
|
|
return(ret_val);
|
|
} // PerformanceCounters::Close
|
|
|
|
|
|
uint64_t
|
|
PerformanceCounters::Inc(
|
|
unsigned Index)
|
|
{
|
|
uint64_t ret_val;
|
|
|
|
ret_val=0;
|
|
if (Index<m_CounterSize)
|
|
{
|
|
volatile uint64_t * val_ptr;
|
|
|
|
val_ptr=&m_Counter[Index];
|
|
|
|
# if ULONG_MAX != 4294967295UL
|
|
#ifdef OS_SOLARIS
|
|
atomic_inc_64(val_ptr);
|
|
#else
|
|
__sync_add_and_fetch(val_ptr, 1);
|
|
#endif
|
|
#else
|
|
// hack fest for 64 bit semi-atomic on 32bit machine
|
|
uint32_t ret_32, * ptr_32;
|
|
|
|
ptr_32=(uint32_t *)&val_ptr;
|
|
ret_32=__sync_add_and_fetch(ptr_32, 1);
|
|
if (0==ret_32)
|
|
{
|
|
++ptr_32;
|
|
__sync_add_and_fetch(ptr_32, 1);
|
|
} // if
|
|
#endif
|
|
ret_val=*val_ptr;
|
|
} // if
|
|
|
|
return(ret_val);
|
|
} // PerformanceCounters::Inc
|
|
|
|
|
|
uint64_t
|
|
PerformanceCounters::Dec(
|
|
unsigned Index)
|
|
{
|
|
uint64_t ret_val;
|
|
|
|
ret_val=0;
|
|
if (Index<m_CounterSize)
|
|
{
|
|
volatile uint64_t * val_ptr;
|
|
|
|
val_ptr=&m_Counter[Index];
|
|
|
|
# if ULONG_MAX != 4294967295UL
|
|
#ifdef OS_SOLARIS
|
|
atomic_dec_64(val_ptr);
|
|
#else
|
|
__sync_sub_and_fetch(val_ptr, 1);
|
|
#endif
|
|
#else
|
|
// hack fest for 64 bit semi-atomic on 32bit machine
|
|
uint32_t ret_32, * ptr_32;
|
|
|
|
ptr_32=(uint32_t *)&val_ptr;
|
|
ret_32=__sync_sub_and_fetch(ptr_32, 1);
|
|
if (0xFFFFFFFF==ret_32)
|
|
{
|
|
++ptr_32;
|
|
__sync_sub_and_fetch(ptr_32, 1);
|
|
} // if
|
|
#endif
|
|
ret_val=*val_ptr;
|
|
} // if
|
|
|
|
return(ret_val);
|
|
} // PerformanceCounters::Dec
|
|
|
|
|
|
uint64_t
|
|
PerformanceCounters::Add(
|
|
unsigned Index,
|
|
uint64_t Amount)
|
|
{
|
|
uint64_t ret_val;
|
|
|
|
ret_val=0;
|
|
if (Index<m_CounterSize)
|
|
{
|
|
volatile uint64_t * val_ptr;
|
|
|
|
val_ptr=&m_Counter[Index];
|
|
|
|
# if ULONG_MAX != 4294967295UL
|
|
#ifdef OS_SOLARIS
|
|
ret_val=atomic_add_64_nv(val_ptr, Amount);
|
|
#else
|
|
ret_val=__sync_add_and_fetch(val_ptr, Amount);
|
|
#endif
|
|
#else
|
|
// hack fest for 64 bit semi-atomic on 32bit machine
|
|
uint32_t old_32, ret_32, * ptr_32;
|
|
|
|
ptr_32=(uint32_t *)&val_ptr;
|
|
old_32=*ptr_32;
|
|
ret_32=__sync_add_and_fetch(ptr_32, Amount);
|
|
if (ret_32<old_32)
|
|
{
|
|
++ptr_32;
|
|
__sync_add_and_fetch(ptr_32, 1);
|
|
} // if
|
|
|
|
ret_val=*val_ptr;
|
|
#endif
|
|
} // if
|
|
|
|
return(ret_val);
|
|
} // PerformanceCounters::Add
|
|
|
|
|
|
uint64_t
|
|
PerformanceCounters::Value(
|
|
unsigned Index) const
|
|
{
|
|
uint64_t ret_val;
|
|
|
|
ret_val=0;
|
|
if (Index<m_CounterSize)
|
|
{
|
|
ret_val=m_Counter[Index];
|
|
} // if
|
|
|
|
return(ret_val);
|
|
} // SstCounters::Value
|
|
|
|
|
|
void
|
|
PerformanceCounters::Set(
|
|
unsigned Index,
|
|
uint64_t Amount)
|
|
{
|
|
if (Index<m_CounterSize)
|
|
{
|
|
volatile uint64_t * val_ptr;
|
|
|
|
val_ptr=&m_Counter[Index];
|
|
|
|
*val_ptr=Amount;
|
|
} // if
|
|
|
|
return;
|
|
} // PerformanceCounters::Set
|
|
|
|
|
|
volatile const uint64_t *
|
|
PerformanceCounters::GetPtr(
|
|
unsigned Index) const
|
|
{
|
|
const volatile uint64_t * ret_ptr;
|
|
|
|
if (Index<m_CounterSize)
|
|
ret_ptr=&m_Counter[Index];
|
|
else
|
|
ret_ptr=&m_BogusCounter;
|
|
|
|
return(ret_ptr);
|
|
|
|
} // PerformanceCounters::GetPtr
|
|
|
|
|
|
const char *
|
|
PerformanceCounters::GetNamePtr(
|
|
unsigned Index)
|
|
{
|
|
const char * ret_ptr;
|
|
|
|
if (Index<ePerfCountEnumSize)
|
|
ret_ptr=m_PerfCounterNames[Index];
|
|
else
|
|
ret_ptr="???";
|
|
|
|
return(ret_ptr);
|
|
|
|
} // PerformanceCounters::GetPtr
|
|
|
|
|
|
int PerformanceCounters::m_PerfSharedId=-1;
|
|
int PerformanceCounters::m_LastError=0;
|
|
volatile uint64_t PerformanceCounters::m_BogusCounter=0;
|
|
const char * PerformanceCounters::m_PerfCounterNames[]=
|
|
{
|
|
"ROFileOpen",
|
|
"ROFileClose",
|
|
"ROFileUnmap",
|
|
"RWFileOpen",
|
|
"RWFileClose",
|
|
"RWFileUnmap",
|
|
"ApiOpen",
|
|
"ApiGet",
|
|
"ApiWrite",
|
|
"WriteSleep",
|
|
"WriteWaitImm",
|
|
"WriteWaitLevel0",
|
|
"WriteNewMem",
|
|
"WriteError",
|
|
"WriteNoWait",
|
|
"GetMem",
|
|
"GetImm",
|
|
"GetVersion",
|
|
"SearchLevel[0]",
|
|
"SearchLevel[1]",
|
|
"SearchLevel[2]",
|
|
"SearchLevel[3]",
|
|
"SearchLevel[4]",
|
|
"SearchLevel[5]",
|
|
"SearchLevel[6]",
|
|
"TableCached",
|
|
"TableOpened",
|
|
"TableGet",
|
|
"BGCloseUnmap",
|
|
"BGCompactImm",
|
|
"BGNormal",
|
|
"BGCompactLevel0",
|
|
"BlockFiltered",
|
|
"BlockFilterFalse",
|
|
"BlockCached",
|
|
"BlockRead",
|
|
"BlockFilterRead",
|
|
"BlockValidGet",
|
|
"Debug[0]",
|
|
"Debug[1]",
|
|
"Debug[2]",
|
|
"Debug[3]",
|
|
"Debug[4]",
|
|
"ReadBlockError",
|
|
"DBIterNew",
|
|
"DBIterNext",
|
|
"DBIterPrev",
|
|
"DBIterSeek",
|
|
"DBIterSeekFirst",
|
|
"DBIterSeekLast",
|
|
"DBIterDelete",
|
|
"eleveldbDirect",
|
|
"eleveldbQueued",
|
|
"eleveldbDequeued",
|
|
"elevelRefCreate",
|
|
"elevelRefDelete",
|
|
"ThrottleGauge",
|
|
"ThrottleCounter",
|
|
"ThrottleMicros0",
|
|
"ThrottleKeys0",
|
|
"ThrottleBacklog0",
|
|
"ThrottleCompacts0",
|
|
"ThrottleMicros1",
|
|
"ThrottleKeys1",
|
|
"ThrottleBacklog1",
|
|
"ThrottleCompacts1",
|
|
"BGWriteError",
|
|
"ThrottleWait",
|
|
"ThreadError",
|
|
"BGImmDirect",
|
|
"BGImmQueued",
|
|
"BGImmDequeued",
|
|
"BGImmWeighted",
|
|
"BGUnmapDirect",
|
|
"BGUnmapQueued",
|
|
"BGUnmapDequeued",
|
|
"BGUnmapWeighted",
|
|
"BGLevel0Direct",
|
|
"BGLevel0Queued",
|
|
"BGLevel0Dequeued",
|
|
"BGLevel0Weighted",
|
|
"BGCompactDirect",
|
|
"BGCompactQueued",
|
|
"BGCompactDequeued",
|
|
"BGCompactWeighted",
|
|
"FileCacheInsert",
|
|
"FileCacheRemove",
|
|
"BlockCacheInsert",
|
|
"BlockCacheRemove",
|
|
"ApiDelete"
|
|
};
|
|
|
|
|
|
int
|
|
PerformanceCounters::LookupCounter(
|
|
const char * Name)
|
|
{
|
|
int index,loop;
|
|
|
|
index=-1;
|
|
|
|
if (NULL!=Name && '\0'!=*Name)
|
|
{
|
|
for (loop=0; loop<ePerfCountEnumSize && -1==index; ++loop)
|
|
{
|
|
if (0==strcmp(m_PerfCounterNames[loop], Name))
|
|
index=loop;
|
|
} // loop
|
|
} // if
|
|
|
|
return(index);
|
|
};
|
|
|
|
void
|
|
PerformanceCounters::Dump()
|
|
{
|
|
int loop;
|
|
|
|
printf(" m_Version: %u\n", m_Version);
|
|
printf(" m_CounterSize: %u\n", m_CounterSize);
|
|
|
|
for (loop=0; loop<ePerfCountEnumSize; ++loop)
|
|
{
|
|
printf(" %s: %" PRIu64 "\n", m_PerfCounterNames[loop], m_Counter[loop]);
|
|
} // loop
|
|
}; // Dump
|
|
|
|
} // namespace leveldb
|