Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
counter.cpp
Go to the documentation of this file.
1 /* Copyright (c) 2010 Wildfire Games
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining
4  * a copy of this software and associated documentation files (the
5  * "Software"), to deal in the Software without restriction, including
6  * without limitation the rights to use, copy, modify, merge, publish,
7  * distribute, sublicense, and/or sell copies of the Software, and to
8  * permit persons to whom the Software is furnished to do so, subject to
9  * the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included
12  * in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  */
22 
23 /*
24  * Interface for counter implementations
25  */
26 
27 #include "precompiled.h"
29 
30 #include "lib/alignment.h"
31 #include "lib/sysdep/cpu.h" // cpu_CAS
32 
38 // to add a new counter type, simply include its header here and
39 // insert a case in ConstructCounterAt's switch statement.
40 
41 
42 //-----------------------------------------------------------------------------
43 // create/destroy counters
44 
45 /**
46  * @param id
47  * @param address
48  * @param size Maximum allowable size [bytes] of the subclass instance
49  * @return pointer to a newly constructed ICounter subclass of type <id> at
50  * the given address, or 0 iff the ID is invalid.
51  **/
52 static ICounter* ConstructCounterAt(size_t id, void* address, size_t size)
53 {
54  // rationale for placement new: see call site.
55 
56  // counters are chosen according to the following order. rationale:
57  // - TSC must come before QPC and PMT to make sure a bug in the latter on
58  // Pentium systems doesn't come up.
59  // - PMT works, but is inexplicably slower than QPC on a PIII Mobile.
60  // - TGT really isn't as safe as the others, so it should be last.
61  // - low-overhead and high-resolution counters are preferred.
62  switch(id)
63  {
64  case 0:
65  return CreateCounterHPET(address, size);
66  case 1:
67  return CreateCounterTSC(address, size);
68  case 2:
69  return CreateCounterQPC(address, size);
70  case 3:
71  return CreateCounterPMT(address, size);
72  case 4:
73  return CreateCounterTGT(address, size);
74  default:
75  return 0;
76  }
77 }
78 
79 
80 static volatile intptr_t isCounterAllocated;
81 
83 {
84  // we placement-new the Counter classes in a static buffer.
85  // this is dangerous, but we are careful to ensure alignment. it is
86  // unusual and thus bad, but there's also one advantage: we avoid
87  // using global operator new before the CRT is initialized (risky).
88  //
89  // alternatives:
90  // - defining as static doesn't work because the ctors (necessary for
91  // vptr initialization) run during _cinit, which comes after our
92  // first use of them.
93  // - using static_calloc isn't possible because we don't know the
94  // size until after the alloc / placement new.
95 
96  if(!cpu_CAS(&isCounterAllocated, 0, 1))
97  DEBUG_WARN_ERR(ERR::LOGIC); // static counter memory is already in use!
98 
99  static const size_t memSize = 200;
100  static u8 mem[memSize];
101  u8* alignedMem = (u8*)Align<16>((uintptr_t)mem);
102  const size_t bytesLeft = mem+memSize - alignedMem;
103  ICounter* counter = ConstructCounterAt(id, alignedMem, bytesLeft);
104 
105  return counter;
106 }
107 
108 
110 {
111  ENSURE(counter);
112  counter->Shutdown();
113  counter->~ICounter(); // must be called due to placement new
114  counter = 0;
115 
116  isCounterAllocated = 0;
117 }
ICounter * CreateCounterPMT(void *address, size_t size)
Definition: pmt.cpp:111
#define u8
Definition: types.h:39
virtual ~ICounter()
Definition: counter.h:36
const Status LOGIC
Definition: status.h:409
static ICounter * counter
Definition: whrt.cpp:96
ICounter * CreateCounterQPC(void *address, size_t size)
Definition: qpc.cpp:153
ICounter * CreateCounterHPET(void *address, size_t size)
Definition: hpet.cpp:229
#define ENSURE(expr)
ensure the expression &lt;expr&gt; evaluates to non-zero.
Definition: debug.h:282
static volatile intptr_t isCounterAllocated
Definition: counter.cpp:80
virtual void Shutdown()=0
#define DEBUG_WARN_ERR(status)
display the error dialog with text corresponding to the given error code.
Definition: debug.h:331
bool cpu_CAS(volatile intptr_t *location, intptr_t expected, intptr_t newValue)
atomic &quot;compare and swap&quot;.
Definition: arm.cpp:36
ICounter * CreateCounterTSC(void *address, size_t size)
Definition: tsc.cpp:255
void DestroyCounter(ICounter *&counter)
shut down the counter, free its resources and zero its pointer.
Definition: counter.cpp:109
ICounter * CreateCounterTGT(void *address, size_t size)
Definition: tgt.cpp:102
static ICounter * ConstructCounterAt(size_t id, void *address, size_t size)
Definition: counter.cpp:52
ICounter * CreateCounter(size_t id)
Definition: counter.cpp:82