1//
2// Copyright (c) Microsoft. All rights reserved.
3// Licensed under the MIT license. See LICENSE file in the project root for full license information.
4//
5
6#include "standardpch.h"
7#include "methodcallsummarizer.h"
8#include "logging.h"
9#include "spmiutil.h"
10
11MethodCallSummarizer::MethodCallSummarizer(WCHAR* logPath)
12{
13 numNames = 0;
14 names = nullptr;
15 counts = nullptr;
16
17 WCHAR* executableName = GetCommandLineW();
18 const WCHAR* dataFileExtension = W(".csv");
19
20 dataFileName = getResultFileName(logPath, executableName, dataFileExtension);
21}
22
23// lots of ways will be faster.. this happens to be decently simple and good enough for the task at hand and nicely
24// sorts the output. in this approach the most commonly added items are at the top of the list... 60% landed in the
25// first
26// three slots in short runs
27void MethodCallSummarizer::AddCall(const char* name)
28{
29 // if we can find it already in our list, increment the count
30 for (int i = 0; i < numNames; i++)
31 {
32 if (strcmp(name, names[i]) == 0)
33 {
34 counts[i]++;
35 for (i = 1; i < numNames; i++)
36 if (counts[i] > counts[i - 1])
37 {
38 unsigned int tempui = counts[i - 1];
39 counts[i - 1] = counts[i];
40 counts[i] = tempui;
41 char* tempc = names[i - 1];
42 names[i - 1] = names[i];
43 names[i] = tempc;
44 }
45 return;
46 }
47 }
48
49 // else we didn't find it, so add it
50 char** tnames = names;
51 unsigned int* tcounts = counts;
52
53 names = new char*[numNames + 1];
54 if (tnames != nullptr)
55 {
56 memcpy(names, tnames, numNames * sizeof(char*));
57 delete tnames;
58 }
59
60 size_t tlen = strlen(name);
61 names[numNames] = new char[tlen + 1];
62 memcpy(names[numNames], name, tlen + 1);
63
64 counts = new unsigned int[numNames + 1];
65 if (tcounts != nullptr)
66 {
67 memcpy(counts, tcounts, numNames * sizeof(unsigned int));
68 delete tcounts;
69 }
70 counts[numNames] = 1;
71
72 numNames++;
73}
74
75void MethodCallSummarizer::SaveTextFile()
76{
77 char buff[512];
78 DWORD bytesWritten = 0;
79 HANDLE hFile = CreateFileW(dataFileName, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
80 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
81
82 if (hFile == INVALID_HANDLE_VALUE)
83 {
84 LogError("Couldn't open file '%ws': error %d", dataFileName, ::GetLastError());
85 return;
86 }
87
88 DWORD len = (DWORD)sprintf_s(buff, 512, "FunctionName,Count\n");
89 WriteFile(hFile, buff, len, &bytesWritten, NULL);
90
91 for (int i = 0; i < numNames; i++)
92 {
93 len = sprintf_s(buff, 512, "%s,%u\n", names[i], counts[i]);
94 WriteFile(hFile, buff, len, &bytesWritten, NULL);
95 }
96 CloseHandle(hFile);
97}
98