1 /*
2 Copyright (c) 2009-2012, Intel Corporation
3 All rights reserved.
4 
5 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
6 
7     * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
8     * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
9     * Neither the name of Intel Corporation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
10 
11 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
12 */
13 //
14 // asynchonous CPU conters
15 //
16 // contact: Thomas Willhalm
17 
18 #ifndef CPUASYNCHCOUNTER_HEADER
19 #define CPUASYNCHCOUNTER_HEADER
20 
21 
22 /*!     \file cpuasynchcounter.h
23         \brief Implementation of a POSIX thread that periodically saves the current state of counters and exposes them to other threads
24 */
25 
26 #include <pthread.h>
27 #include <stdlib.h>
28 #include "cpucounters.h"
29 
30 #define DELAY 1 // in seconds
31 
32 using namespace pcm;
33 
34 void * UpdateCounters(void *);
35 
36 class AsynchronCounterState {
37     PCM * m;
38 
39     CoreCounterState * cstates1, * cstates2;
40     SocketCounterState * skstates1, * skstates2;
41     SystemCounterState sstate1, sstate2;
42 
43     pthread_t UpdateThread;
44     pthread_mutex_t CounterMutex;
45 
46     friend void * UpdateCounters(void *);
47 
48     AsynchronCounterState(const AsynchronCounterState &) = delete;
49     const AsynchronCounterState & operator = (const AsynchronCounterState &) = delete;
50 
51 public:
AsynchronCounterState()52     AsynchronCounterState()
53     {
54         m = PCM::getInstance();
55         PCM::ErrorCode status = m->program();
56         if (status != PCM::Success)
57         {
58             std::cerr << "\nCannot access CPU counters. Try to run pcm.x 1 to check the PMU access status.\n\n";
59             exit(-1);
60         }
61 
62         cstates1 = new  CoreCounterState[m->getNumCores()];
63         cstates2 = new  CoreCounterState[m->getNumCores()];
64         skstates1 = new SocketCounterState[m->getNumSockets()];
65         skstates2 = new SocketCounterState[m->getNumSockets()];
66 
67         for (uint32 i = 0; i < m->getNumCores(); ++i) {
68             cstates1[i] = getCoreCounterState(i);
69             cstates2[i] = getCoreCounterState(i);
70         }
71 
72         for (uint32 i = 0; i < m->getNumSockets(); ++i) {
73             skstates1[i] = getSocketCounterState(i);
74             skstates2[i] = getSocketCounterState(i);
75         }
76 
77         pthread_mutex_init(&CounterMutex, NULL);
78         pthread_create(&UpdateThread, NULL, UpdateCounters, this);
79     }
~AsynchronCounterState()80     ~AsynchronCounterState()
81     {
82         pthread_cancel(UpdateThread);
83         pthread_mutex_destroy(&CounterMutex);
84         m->cleanup();
85         delete[] cstates1;
86         delete[] cstates2;
87         delete[] skstates1;
88         delete[] skstates2;
89     }
90 
getNumCores()91     uint32 getNumCores()
92     { return m->getNumCores(); }
93 
getNumSockets()94     uint32 getNumSockets()
95     { return m->getNumSockets(); }
96 
getQPILinksPerSocket()97     uint32 getQPILinksPerSocket()
98     {
99         return m->getQPILinksPerSocket();
100     }
101 
getSocketId(uint32 c)102     uint32 getSocketId(uint32 c)
103     {
104         return m->getSocketId(c);
105     }
106 
107     template <typename T, T func(CoreCounterState const &)>
get(uint32 core)108     T get(uint32 core)
109     {
110         pthread_mutex_lock(&CounterMutex);
111         T value = func(cstates2[core]);
112         pthread_mutex_unlock(&CounterMutex);
113         return value;
114     }
115     template <typename T, T func(CoreCounterState const &, CoreCounterState const &)>
get(uint32 core)116     T get(uint32 core)
117     {
118         pthread_mutex_lock(&CounterMutex);
119         T value = func(cstates1[core], cstates2[core]);
120         pthread_mutex_unlock(&CounterMutex);
121         return value;
122     }
123 
124     template <typename T, T func(int, CoreCounterState const &, CoreCounterState const &)>
get(int param,uint32 core)125     T get(int param, uint32 core)
126     {
127         pthread_mutex_lock(&CounterMutex);
128         T value = func(param, cstates1[core], cstates2[core]);
129         pthread_mutex_unlock(&CounterMutex);
130         return value;
131     }
132 
133     template <typename T, T func(SocketCounterState const &)>
getSocket(uint32 socket)134     T getSocket(uint32 socket)
135     {
136         pthread_mutex_lock(&CounterMutex);
137         T value = func(skstates2[socket]);
138         pthread_mutex_unlock(&CounterMutex);
139         return value;
140     }
141 
142     template <typename T, T func(SocketCounterState const &, SocketCounterState const &)>
getSocket(uint32 socket)143     T getSocket(uint32 socket)
144     {
145         pthread_mutex_lock(&CounterMutex);
146         T value = func(skstates1[socket], skstates2[socket]);
147         pthread_mutex_unlock(&CounterMutex);
148         return value;
149     }
150 
151     template <typename T, T func(int, SocketCounterState const &, SocketCounterState const &)>
getSocket(int param,uint32 socket)152     T getSocket(int param, uint32 socket)
153     {
154         pthread_mutex_lock(&CounterMutex);
155         T value = func(param, skstates1[socket], skstates2[socket]);
156         pthread_mutex_unlock(&CounterMutex);
157         return value;
158     }
159 
160     template <typename T, T func(uint32, uint32, SystemCounterState const &, SystemCounterState const &)>
getSocket(uint32 socket,uint32 param)161     T getSocket(uint32 socket, uint32 param)
162     {
163         pthread_mutex_lock(&CounterMutex);
164         T value = func(socket, param, sstate1, sstate2);
165         pthread_mutex_unlock(&CounterMutex);
166         return value;
167     }
168 
169     template <typename T, T func(SystemCounterState const &, SystemCounterState const &)>
getSystem()170     T getSystem()
171     {
172         pthread_mutex_lock(&CounterMutex);
173         T value = func(sstate1, sstate2);
174         pthread_mutex_unlock(&CounterMutex);
175         return value;
176     }
177 
178     template <typename T, T func(int, SystemCounterState const &, SystemCounterState const &)>
getSystem(int param)179     T getSystem(int param)
180     {
181         pthread_mutex_lock(&CounterMutex);
182         T value = func(param, sstate1, sstate2);
183         pthread_mutex_unlock(&CounterMutex);
184         return value;
185     }
186 };
187 
UpdateCounters(void * state)188 void * UpdateCounters(void * state)
189 {
190     AsynchronCounterState * s = (AsynchronCounterState *)state;
191 
192     while (true) {
193         pthread_mutex_lock(&(s->CounterMutex));
194         for (uint32 core = 0; core < s->m->getNumCores(); ++core) {
195             s->cstates1[core] = std::move(s->cstates2[core]);
196             s->cstates2[core] = s->m->getCoreCounterState(core);
197         }
198 
199         for (uint32 socket = 0; socket < s->m->getNumSockets(); ++socket) {
200             s->skstates1[socket] = std::move(s->skstates2[socket]);
201             s->skstates2[socket] = s->m->getSocketCounterState(socket);
202         }
203 
204         s->sstate1 = std::move(s->sstate2);
205         s->sstate2 = s->m->getSystemCounterState();
206 
207         pthread_mutex_unlock(&(s->CounterMutex));
208         sleep(1);
209     }
210     return NULL;
211 }
212 
213 #endif
214