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 | |
11 | MethodCallSummarizer::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 |
27 | void 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 | |
75 | void 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 | |