| 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 | |