mirror of
https://gitea.wildfiregames.com/0ad/0ad.git
synced 2026-07-16 20:35:18 +00:00
bd0d0c0026
cpu: avoid measuring cpu freq if possible ia32: cleanup, fix #cores detection on AMD (they're incompatible, *sigh*), add ia32_Generation wcpu: remove IsThrottling code (clunky and not necessary - we rely on ia32's feature bit detection instead) counter: move whrt's counter create code here qpc: update comment tsc: finalize IsSafe implementation, remove per-thread stuff (since it cannot be made to work) whrt: cleanup, remove calibration code (no longer needed) This was SVN commit r5121.
107 lines
2.9 KiB
C++
107 lines
2.9 KiB
C++
/**
|
|
* =========================================================================
|
|
* File : counter.cpp
|
|
* Project : 0 A.D.
|
|
* Description : Interface for counter implementations
|
|
* =========================================================================
|
|
*/
|
|
|
|
// license: GPL; see lib/license.txt
|
|
|
|
#include "precompiled.h"
|
|
#include "counter.h"
|
|
|
|
#include "lib/bits.h"
|
|
|
|
#include "tsc.h"
|
|
#include "hpet.h"
|
|
#include "pmt.h"
|
|
#include "qpc.h"
|
|
#include "tgt.h"
|
|
// to add a new counter type, simply include its header here and
|
|
// insert a case in ConstructCounterAt's switch statement.
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// create/destroy counters
|
|
|
|
/**
|
|
* @return pointer to a newly constructed ICounter subclass of type <id> at
|
|
* the given address, or 0 iff the ID is invalid.
|
|
* @param size receives the size [bytes] of the created instance.
|
|
**/
|
|
static ICounter* ConstructCounterAt(uint id, void* address, size_t& size)
|
|
{
|
|
// rationale for placement new: see call site.
|
|
#define CREATE(impl)\
|
|
size = sizeof(Counter##impl);\
|
|
return new(address) Counter##impl();
|
|
|
|
#include "lib/nommgr.h" // MMGR interferes with placement new
|
|
|
|
// counters are chosen according to the following order. rationale:
|
|
// - TSC must come before QPC and PMT to make sure a bug in the latter on
|
|
// Pentium systems doesn't come up.
|
|
// - PMT works, but is inexplicably slower than QPC on a PIII Mobile.
|
|
// - TGT really isn't as safe as the others, so it should be last.
|
|
// - low-overhead and high-resolution counters are preferred.
|
|
switch(id)
|
|
{
|
|
case 0:
|
|
CREATE(HPET)
|
|
case 1:
|
|
CREATE(TSC)
|
|
case 2:
|
|
CREATE(QPC)
|
|
case 3:
|
|
CREATE(PMT)
|
|
case 4:
|
|
CREATE(TGT)
|
|
default:
|
|
size = 0;
|
|
return 0;
|
|
}
|
|
|
|
#include "lib/mmgr.h"
|
|
|
|
#undef CREATE
|
|
}
|
|
|
|
ICounter* CreateCounter(uint id)
|
|
{
|
|
// we placement-new the Counter classes in a static buffer.
|
|
// this is dangerous, but we are careful to ensure alignment. it is
|
|
// unusual and thus bad, but there's also one advantage: we avoid
|
|
// using global operator new before the CRT is initialized (risky).
|
|
//
|
|
// alternatives:
|
|
// - defining as static doesn't work because the ctors (necessary for
|
|
// vptr initialization) run during _cinit, which comes after our
|
|
// first use of them.
|
|
// - using static_calloc isn't possible because we don't know the
|
|
// size until after the alloc / placement new.
|
|
static const size_t MEM_SIZE = 200; // checked below
|
|
static u8 mem[MEM_SIZE];
|
|
static u8* nextMem = mem;
|
|
|
|
u8* addr = (u8*)round_up((uintptr_t)nextMem, 16);
|
|
size_t size;
|
|
ICounter* counter = ConstructCounterAt(id, addr, size);
|
|
|
|
nextMem = addr+size;
|
|
debug_assert(nextMem < mem+MEM_SIZE); // had enough room?
|
|
|
|
return counter;
|
|
}
|
|
|
|
|
|
void DestroyCounter(ICounter*& counter)
|
|
{
|
|
if(!counter)
|
|
return;
|
|
|
|
counter->Shutdown();
|
|
counter->~ICounter(); // must be called due to placement new
|
|
counter = 0;
|
|
}
|