libjmmcg  release_579_6_g8cffd
A C++ library containing an eclectic mix of useful, advanced components.
NTPerformanceObjects.cpp
Go to the documentation of this file.
1 /******************************************************************************
2 ** Copyright © 2002 by J.M.McGuiness, coder@hussar.me.uk
3 **
4 ** This library is free software; you can redistribute it and/or
5 ** modify it under the terms of the GNU Lesser General Public
6 ** License as published by the Free Software Foundation; either
7 ** version 2.1 of the License, or (at your option) any later version.
8 **
9 ** This library is distributed in the hope that it will be useful,
10 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 ** Lesser General Public License for more details.
13 **
14 ** You should have received a copy of the GNU Lesser General Public
15 ** License along with this library; if not, write to the Free Software
16 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18 
19 #include"stdafx.h"
20 
21 #ifdef _DEBUG
22 #define new DEBUG_NEW
23 #undef THIS_FILE
24 static char THIS_FILE[] = __FILE__;
25 #endif
26 
28 #include"../DumpWinMsg.hpp"
29 
30 #pragma comment(lib, "loadperf.lib")
31 
32 using namespace libjmmcg;
33 using namespace NTUtils;
34 
35 /////////////////////////////////////////////////////////////////////////////
36 
37 JMMCG_REVISION_CONSTANT(_T(LIBJMMCG_VERSION_NUMBER))
38 
39 /////////////////////////////////////////////////////////////////////////////
40 
41 template <> HeapID NTPerformanceObjects::sm_char_heap_type::GetHeapID(void) {
42  return HeapID(initial_shared_memory_size, string_shared_memory_name, string_shared_mutex_name, &NTPerformanceObjects::allow_all);
43 }
44 
45 template <> HeapID NTPerformanceObjects::nt_po_heap_type::GetHeapID(void) {
46  return HeapID(initial_shared_memory_size, ptr_shared_memory_name, ptr_shared_mutex_name, &NTPerformanceObjects::allow_all);
47 }
48 
49 template <> HeapID NTPerformanceObjects::sm_string_heap_type::GetHeapID(void) {
50  return HeapID(initial_shared_memory_size, list_shared_memory_name, list_shared_mutex_name, &NTPerformanceObjects::allow_all);
51 }
52 
53 template <> HeapID NTPerformanceObjects::cpp_po_heap_type::GetHeapID(void) {
54  return HeapID(initial_shared_memory_size, map_shared_memory_name, map_shared_mutex_name, &NTPerformanceObjects::allow_all);
55 }
56 
57 // I need this linkage to ensure I have a standard decorated name to us in the "NTPerformanceObjects", below.
58 // I can't put these in a class because of the name mangling.
59 
60 extern "C"
61 {
62 
63  __declspec(dllexport)
64  DWORD CALLBACK OpenPerformanceData(LPWSTR lpDeviceNames) {
65  NTUtils::CSectionLock lock(NTPerformanceObjects::perf_ctr_map_sect);
66  NTPerformanceObjects::nt_event_log.Log(NTUtils::EventLog::err_information, NTUtils::EventLog::cat_custom1, "OpenPerformanceData(...) : Connecting ...");
67  std::string str;
68  try {
69  NTPerformanceObjects::cpp_po_heap_type cpp_po_heap(HeapID(initial_shared_memory_size, map_shared_memory_names, &NTPerformanceObjects::allow_all));
70  NTPerformanceObjects::cpp_performance_objects_type * const cpp_performance_objects=(NTPerformanceObjects::cpp_performance_objects_type *)cpp_po_heap;
71  if (cpp_performance_objects->find(reinterpret_cast<char *>(lpDeviceNames))==cpp_performance_objects->end()) {
72  str="OpenPerformanceData(...) : The device name does not exist:'";
73  str+=reinterpret_cast<char *>(lpDeviceNames);
74  str+="'";
75  NTPerformanceObjects::nt_event_log.Log(NTUtils::EventLog::err_information, NTUtils::EventLog::cat_custom1, str);
76  return ERROR_DEV_NOT_EXIST;
77  }
78  return NTPerformanceObjects::Open((*cpp_performance_objects)[reinterpret_cast<char *>(lpDeviceNames)]);
79  } catch (std::exception err) {
80  str="OpenPerformanceData(...) : Connection failure.\nSTL exception caught.\nDetails:\n";
81  str+=err.what();
82  NTPerformanceObjects::nt_event_log.Log(NTUtils::EventLog::err_error, NTUtils::EventLog::cat_custom1, str);
83  } catch (...) {
84  NTPerformanceObjects::nt_event_log.Log(NTUtils::EventLog::err_error, NTUtils::EventLog::cat_custom1, "OpenPerformanceData(...) : Connection failure.\nUnknown exception caught.");
85  }
86  return ERROR_INVALID_FUNCTION;
87  }
88 
89  __declspec(dllexport)
90  DWORD WINAPI CollectPerformanceData(LPWSTR lpwszValue, LPVOID *lppData, LPDWORD lpcbBytes, LPDWORD lpcObjectTypes) {
91  NTUtils::CSectionLock lock(NTPerformanceObjects::perf_ctr_map_sect);
92  NTPerformanceObjects::nt_event_log.Log(NTUtils::EventLog::err_information, NTUtils::EventLog::cat_custom2, "CollectPerformanceData(...) : Collecting...");
93  std::string str;
94  try {
95  NTPerformanceObjects::cpp_po_heap_type cpp_po_heap(HeapID(initial_shared_memory_size, map_shared_memory_names, &NTPerformanceObjects::allow_all));
96  NTPerformanceObjects::cpp_performance_objects_type * const cpp_performance_objects=(NTPerformanceObjects::cpp_performance_objects_type *)cpp_po_heap;
97  std::auto_ptr<char> n_value(new char[wcslen(lpwszValue)]);
98  CharToOemW(lpwszValue, n_value.get());
99  str="CollectPerformanceData(...) : Collection parameters:\nCollection load type:'";
100  str+=n_value.get();
101  str+="'";
102  NTPerformanceObjects::nt_event_log.Log(NTUtils::EventLog::err_information, NTUtils::EventLog::cat_custom2, str);
103  if (cpp_performance_objects->find(n_value.get())==cpp_performance_objects->end()) {
104  str="CollectPerformanceData(...) : The device name does not exist:'";
105  str+=n_value.get();
106  str+="'";
107  NTPerformanceObjects::nt_event_log.Log(NTUtils::EventLog::err_error, NTUtils::EventLog::cat_custom2, str);
108  return ERROR_DEV_NOT_EXIST;
109  }
110  return NTPerformanceObjects::Collect((*cpp_performance_objects)[n_value.get()], lpwszValue, lppData, lpcbBytes, lpcObjectTypes);
111  } catch (std::exception err) {
112  str="CollectPerformanceData(...) : Connection failure.\nSTL exception caught.\nDetails:";
113  str+=err.what();
114  NTPerformanceObjects::nt_event_log.Log(NTUtils::EventLog::err_error, NTUtils::EventLog::cat_custom2, str);
115  } catch (...) {
116  NTPerformanceObjects::nt_event_log.Log(NTUtils::EventLog::err_error, NTUtils::EventLog::cat_custom2, "CollectPerformanceData(...) : Connection failure.\nUnknown exception caught.");
117  }
118  *lpcbBytes=0;
119  *lpcObjectTypes=0;
120  return ERROR_INVALID_FUNCTION;
121  }
122 
123  __declspec(dllexport)
124  DWORD WINAPI ClosePerformanceData(void) {
125  NTUtils::CSectionLock lock(NTPerformanceObjects::perf_ctr_map_sect);
126  NTPerformanceObjects::nt_event_log.Log(NTUtils::EventLog::err_information, NTUtils::EventLog::cat_custom3, "ClosePerformanceData() : Disconnecting.");
127  std::string str;
128  try {
129  return NTPerformanceObjects::Close();
130  } catch (std::exception err) {
131  str="CollectPerformanceData(...) : Connection failure.\nSTL exception caught.\nDetails:";
132  str+=err.what();
133  NTPerformanceObjects::nt_event_log.Log(NTUtils::EventLog::err_error, NTUtils::EventLog::cat_custom3, str);
134  } catch (...) {
135  NTPerformanceObjects::nt_event_log.Log(NTUtils::EventLog::err_error, NTUtils::EventLog::cat_custom3, "CollectPerformanceData(...) : Connection failure.\nUnknown exception caught.");
136  }
137  return ERROR_INVALID_FUNCTION;
138  }
139 }
140 
141 /*
142  NT specific class for creating a generic performance monitoring object.
143 */
144 
145 // Making this a static gives errors when trying to delete the registry key. It is delete, just
146 // in the wrong order. Serves me right for making it a static.
147 NTUtils::EventLog NTPerformanceObjects::nt_event_log("NTPerformanceObjects");
150 
151 inline
152 NTPerformanceObjects::NTPerformanceObjects(const std::string &obj_prefix, const std::pair< std::string, std::string > &lang_details, const PerfObjectDetails &perf_obj_details, const bool q) :
153  quiet( q ),
154  driver_name( TempPerfINIFile::make_driver_name(perf_obj_details.object.name) ),
162 {
163  if (!num_ctrs) {
164  std::cerr << "NTPerformanceObjects::NTPerformanceObjects(...) : Performance object: '" << driver_name << "' must have at least one counter." << std::endl;
165  return;
166  }
167 /* cpp_performance_objects=cpp_po_heap.Allocate(1, NULL);
168  cpp_po_heap.Construct(cpp_performance_objects,cpp_performance_objects_type());
169  if (cpp_performance_objects->find(driver_name.c_str())!=cpp_performance_objects->end()) {
170  std::cerr << "NTPerformanceObjects::NTPerformanceObjects(...) : Performance object: '" << driver_name << "' already exists. Cannot have duplicate performance objects." << std::endl;
171  return;
172  }
173  // Make sure that nothing can access the map whilst it is being modified, especially those
174  // "C" global fns (above).
175  NTUtils::CSectionLock lock(perf_ctr_map_sect);
176  // Add the new performance counter object to the map, so that the "C" fns above will
177  // be able to access this new object.
178  (*cpp_performance_objects)[driver_name.c_str()]=this;
179 */conststd::stringctr_name("SYSTEM\\CurrentControlSet\\Services\\"+driver_name);
180 // assert(cpp_performance_objects->find(driver_name.c_str())!=cpp_performance_objects->end());
181  if (perf_key.Open(HKEY_LOCAL_MACHINE, ctr_name)==ERROR_SUCCESS) {
182  std::cerr << "NTPerformanceObjects::NTPerformanceObjects(...) : Performance counter '" << ctr_name << "' already created. Cannot have duplicate named counters." << std::endl;
183  } else if (perf_key.Create(HKEY_LOCAL_MACHINE, ctr_name)==ERROR_SUCCESS
184  && perf_perf_key.Create(perf_key.hkey(), "Performance")==ERROR_SUCCESS
185  && perf_link_key.Create(perf_key.hkey(), "Linkage")==ERROR_SUCCESS) {
186  size_t total_ctr_size=0;
187  std::set< PerfObjectDetails::PerfCtrDetails >::const_iterator iter( perf_obj_details.counters.begin() );
188  while ( iter!=perf_obj_details.counters.end() ) {
189  total_ctr_size+=sizeof(PERF_COUNTER_BLOCK)+iter->size;
190  ++iter;
191  }
192  perf_ctrs_details=reinterpret_cast<perf_ctrs_details_type *>(new char[total_ctr_size]);
193  perf_objects_details=reinterpret_cast<perf_objects_details_type *>(new char[sizeof(PERF_OBJECT_TYPE)+sizeof(PERF_COUNTER_DEFINITION)*perf_obj_details.counters.size()]);
194  perf_objects_details->object_type.HeaderLength=sizeof(PERF_OBJECT_TYPE);
195  perf_objects_details->object_type.DefinitionLength=perf_objects_details->object_type.HeaderLength+sizeof(PERF_COUNTER_DEFINITION)*perf_obj_details.counters.size();
196  perf_objects_details->object_type.TotalByteLength=perf_objects_details->object_type.DefinitionLength+perf_ctrs_details->ctr_block.ByteLength;
197  perf_objects_details->object_type.ObjectNameTitleIndex=0;
198  perf_objects_details->object_type.ObjectNameTitle=0;
199  perf_objects_details->object_type.ObjectHelpTitleIndex=0;
200  perf_objects_details->object_type.ObjectHelpTitle=0;
201  perf_objects_details->object_type.DetailLevel=PERF_DETAIL_ADVANCED;
202  perf_objects_details->object_type.NumCounters=(perf_objects_details->object_type.DefinitionLength-sizeof(PERF_OBJECT_TYPE))/sizeof(PERF_COUNTER_DEFINITION);
203  perf_objects_details->object_type.DefaultCounter=0;
204  perf_objects_details->object_type.NumInstances=PERF_NO_INSTANCES;
205  perf_objects_details->object_type.CodePage=0;
206  iter=perf_obj_details.counters.begin();
207  std::set< PerfObjectDetails::PerfCtrDetails >::size_type i=0;
208  while ( iter!=perf_obj_details.counters.end() ) {
209  reinterpret_cast<perf_ctrs_details_type *>(perf_ctrs_details+i*(sizeof(PERF_COUNTER_BLOCK)+iter->size))->ctr_block.ByteLength=sizeof(PERF_COUNTER_BLOCK)+iter->size;
210  perf_objects_details->ctr_defs[i].ByteLength=sizeof(PERF_COUNTER_DEFINITION);
211  perf_objects_details->ctr_defs[i].CounterNameTitleIndex=(i<<1);
212  perf_objects_details->ctr_defs[i].CounterNameTitle=0;
213  perf_objects_details->ctr_defs[i].CounterHelpTitleIndex=(i<<1);
214  perf_objects_details->ctr_defs[i].CounterHelpTitle=0;
215  perf_objects_details->ctr_defs[i].DefaultScale=0;
216  perf_objects_details->ctr_defs[i].DetailLevel=PERF_DETAIL_ADVANCED;
217  perf_objects_details->ctr_defs[i].CounterType=iter->flags;
218  perf_objects_details->ctr_defs[i].CounterSize=sizeof(perf_ctrs_details->values[i]);
219  perf_objects_details->ctr_defs[i].CounterOffset=(DWORD)&(((perf_ctrs_details_type *)NULL)->values[i]);
220  ++i;
221  ++iter;
222  }
223  char mod_name[MAX_PATH];
224  // Note embedded name of this dll!!!
225  if (GetModuleFileName(GetModuleHandle("cmduilib"), mod_name, MAX_PATH)) {
226  perf_link_key.SetValue(driver_name, "Export", REG_BINARY);
227  perf_perf_key.SetValue(mod_name, "Library");
228  // Note the use of the decorated names!!!!!
229  perf_perf_key.SetValue("_OpenPerformanceData@4", "Open");
230  // Note the use of the decorated names!!!!!
231  perf_perf_key.SetValue("_CollectPerformanceData@16", "Collect");
232  // Note the use of the decorated names!!!!!
233  perf_perf_key.SetValue("_ClosePerformanceData@0", "Close");
234  TempPerfINIFile ini_file(obj_prefix, lang_details, perf_obj_details);
235  long err;
236  // Note bug in "LoadPerfCounterTextStrings(...)" - see MSDN article: 'ID: Q188769'.
237  if ((err=LoadPerfCounterTextStrings(const_cast<char * const>(("x " + ini_file.name()).c_str()), quiet))!=ERROR_SUCCESS) {
238  std::cerr << "NTPerformanceObject::NTPerformanceObject(...) : '" << NTUtils::DumpWinMessage(err) << "'" << std::endl;
239  }
240  } else {
241  std::cerr << "NTPerformanceObjects::NTPerformanceObjects(...) : Failed to get module name. Windows error: '" << NTUtils::DumpWinMessage(::GetLastError()) << "'" << std::endl;
242  }
243  }
244 }
245 
246 inline
248  NTUtils::CSectionLock lock(perf_ctr_map_sect);
249  // Remove this object from the map.
250 // cpp_performance_objects->erase(driver_name.c_str());
251 // cpp_po_heap.Deallocate(cpp_performance_objects,1);
252  long err;
253  // Note bug in "LoadPerfCounterTextStrings(...)" - see MSDN article: 'ID: Q188769'.
254  if ((err=UnloadPerfCounterTextStrings(const_cast<char * const>(("x " + driver_name).c_str()), quiet))!=ERROR_SUCCESS) {
255  std::cerr << "NTPerformanceObjects::~NTPerformanceObjects() : '" << NTUtils::DumpWinMessage(err) << "'" << std::endl;
256  }
257  if (perf_ctrs_details) {
258  delete[] reinterpret_cast<char *>(perf_ctrs_details);
259  }
260  if (perf_objects_details) {
261  delete[] reinterpret_cast<char *>(perf_objects_details);
262  }
263 }
264 
265 inline
267  // Note we are already locked!
268  NTUtils::RegistryKey perf_key;
269  long ret;
270  if ((ret=perf_key.Open(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\" + driver_name + "\\Performance"))==ERROR_SUCCESS) {
271  DWORD size=sizeof(DWORD);
272  DWORD type;
273  DWORD dwFirstCounter;
274  DWORD dwFirstHelp;
275  if ((ret=::RegQueryValueEx(perf_key.hkey(), "First Counter", 0L, &type, (LPBYTE)&dwFirstCounter, &size))!=ERROR_SUCCESS) {
276  std::cerr << "NTPerformanceObjects::Open() : Unable to query key 'HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\" << driver_name << "\\Performance\\First Counter'." << std::endl;
277  std::cerr << "Error is '" << NTUtils::DumpWinMessage(ret) << "'" << std::endl;
278  return ret;
279  }
280  size=sizeof(DWORD);
281  if ((ret=::RegQueryValueEx(perf_key.hkey(), "First Help", 0L, &type, (LPBYTE)&dwFirstHelp, &size))!=ERROR_SUCCESS) {
282  std::cerr << "NTPerformanceObjects::Open() : Unable to query key 'HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\" << driver_name << "\\Performance\\First Help'." << std::endl;
283  std::cerr << "Error is '" << NTUtils::DumpWinMessage(ret) << "'" << std::endl;
284  return ret;
285  }
286  perf_objects_details->object_type.ObjectNameTitleIndex+=dwFirstCounter;
287  perf_objects_details->object_type.ObjectHelpTitleIndex+=dwFirstHelp;
288  perf_objects_details->object_type.DefaultCounter=0;
289  std::set< PerfObjectDetails::PerfCtrDetails >::size_type i=0;
290  while ( i<num_ctrs ) {
291  perf_objects_details->ctr_defs[i].CounterNameTitleIndex+=dwFirstCounter;
292  perf_objects_details->ctr_defs[i].CounterHelpTitleIndex+=dwFirstHelp;
293  ++i;
294  }
295  }
296  return ret;
297 }
298 
299 inline
300 DWORD NTPerformanceObjects::Close(void) {
301  // Note we are already locked!
302  return ERROR_SUCCESS;
303 }
304 
305 inline
306 NTPerformanceObjects::TempPerfINIFile::TempPerfINIFile(const std::string &obj_prefix, const std::pair< std::string, std::string > &lang_details, const PerfObjectDetails &perf_obj_details) : symbol(obj_prefix, perf_obj_details.counters.size()+1) {
307  ini.file() << "[info]" << std::endl;
308  const std::string driver_name(make_driver_name(perf_obj_details.object.name));
309  ini.file() << "drivername=" << driver_name << std::endl;
310  ini.file() << "symbolfile=" << symbol.name() << std::endl;
311  ini.file() << "[languages]" << std::endl;
312  ini.file() << lang_details.first << "=" << lang_details.second << std::endl;
313  ini.file() << "[text]" << std::endl;
314  ini.file() << symbol.names()[0] << "_" << lang_details.first << "_NAME=" << driver_name << std::endl;
315  ini.file() << symbol.names()[0] << "_" << lang_details.first << "_HELP=" << perf_obj_details.object.help << std::endl;
316  std::vector< std::string >::size_type i=1;
317  std::set< PerfObjectDetails::PerfCtrDetails >::const_iterator iter( perf_obj_details.counters.begin() );
318  while (i<symbol.names().size()) {
319  ini.file() << symbol.names()[i] << "_" << lang_details.first << "_NAME=" << iter->details.name << std::endl;
320  ini.file() << symbol.names()[i] << "_" << lang_details.first << "_HELP=" << iter->details.help << std::endl;
321  ++iter;
322  ++i;
323  }
324  ini.file() << std::endl;
325  ini.file().close();
326 }
327 
328 inline
329 NTPerformanceObjects::TempPerfINIFile::~TempPerfINIFile(void) {
330 }
331 
332 inline
333 const std::string &NTPerformanceObjects::TempPerfINIFile::name(void) const {
334  return ini.name();
335 }
336 
337 inline
338 std::string NTPerformanceObjects::TempPerfINIFile::make_driver_name(const std::string &str) {
339  char bname[MAX_PATH];
340  ::GetModuleFileName(NULL,bname,MAX_PATH);
341  std::string name(bname);
342  const std::string::size_type begin=name.find_last_of('\\')+1;
343  name=name.substr(begin, name.find_last_of('.')-begin);
344  return name + " " + str;
345 }
346 
347 inline NTPerformanceObjects::TempPerfINIFile::TempSymbolFile::TempSymbolFile(const std::string &obj_prefix, const std::vector< std::string >::size_type size) {
348  std::vector< std::string >::size_type i=0;
349  while (i<size) {
350  std::stringstream ss;
351  ss << obj_prefix << "_" << i;
352  object_names.push_back(ss.str());
353  symbol.file() << "#define " << object_names[i] << " " << (i<<1) << std::endl;
354  ++i;
355  }
356  symbol.file().close();
357 }
358 
359 inline NTPerformanceObjects::TempPerfINIFile::TempSymbolFile::~TempSymbolFile(void) {
360 }
361 
362 inline
363 const std::string &NTPerformanceObjects::TempPerfINIFile::TempSymbolFile::name(void) const {
364  return symbol.name();
365 }
366 
367 inline const std::vector< std::string > &NTPerformanceObjects::TempPerfINIFile::TempSymbolFile::names(void) const {
368  return object_names;
369 }