// Copyright (c) 2012 DotNetAnywhere
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "Compat.h"
#include "Sys.h"
#include "CLIFile.h"
#include "MetaData.h"
#include "Type.h"
#include "Heap.h"
#include "Finalizer.h"
#include "System.Net.Sockets.Socket.h"
#include "MethodState.h"
static void ShowUsage() {
printf("Usage:\n");
printf("\tdna [-v] <.Net executable to execute> [.Net executable arguments]\n");
printf("\n");
printf("\t-v : Verbose output of files loaded and GC statistics\n");
printf("\t-vv : More verbose output, including methods JITted and types/arrays/generics use\n");
printf("\n");
exit(1);
}
int main(int argc, char **argp) {
tCLIFile *pCLIFile;
char *pFileName;
U32 i;
I32 retValue;
#ifdef DIAG_TOTAL_TIME
U64 startTime;
#endif
if (argc < 2) {
ShowUsage();
}
// Read any flags passed in
for (i=1; i < (U32)argc; i++) {
if (argp[i][0] == '-') {
U32 j;
for (j=1; ; j++) {
switch (argp[i][j]) {
case 0:
goto doneArgs;
case 'v':
logLevel++;
break;
default:
Crash("Invalid argument: -%c", argp[i][1]);
}
}
doneArgs:;
} else {
break;
}
}
JIT_Execute_Init();
MetaData_Init();
Type_Init();
Heap_Init();
Finalizer_Init();
Socket_Init();
#ifdef DIAG_OPCODE_TIMES
#ifdef WIN32
{
HANDLE hProcess = GetCurrentProcess();
SetProcessAffinityMask(hProcess, 1);
}
#endif
memset(opcodeTimes, 0, sizeof(opcodeTimes));
#endif
#ifdef DIAG_OPCODE_USE
memset(opcodeNumUses, 0, sizeof(opcodeNumUses));
#endif
pFileName = argp[i];
pCLIFile = CLIFile_Load(pFileName);
#ifdef DIAG_TOTAL_TIME
startTime = microTime();
#endif
retValue = CLIFile_Execute(pCLIFile, argc - i, argp + i);
#ifdef DIAG_TOTAL_TIME
printf("Total execution time = %d ms\n", (int)((microTime() - startTime) / 1000));
#endif
#ifdef DIAG_GC
printf("Total GC time = %d ms\n", (int)(gcTotalTime / 1000));
#endif
#ifdef DIAG_METHOD_CALLS
{
U32 numMethods, i;
I32 howMany = 25;
tMetaData *pCorLib;
// Report on most-used methods
pCorLib = CLIFile_GetMetaDataForAssembly("mscorlib");
numMethods = pCorLib->tables.numRows[MD_TABLE_METHODDEF];
printf("\nCorLib method usage:\n");
for (; howMany > 0; howMany--) {
tMD_MethodDef *pMethod;
U32 maxCount = 0, maxIndex = 0;
for (i=1; i<=numMethods; i++) {
pMethod = (tMD_MethodDef*)MetaData_GetTableRow(pCorLib, MAKE_TABLE_INDEX(MD_TABLE_METHODDEF, i));
if (pMethod->callCount > maxCount) {
maxCount = pMethod->callCount;
maxIndex = i;
}
}
pMethod = (tMD_MethodDef*)MetaData_GetTableRow(pCorLib, MAKE_TABLE_INDEX(MD_TABLE_METHODDEF, maxIndex));
printf("%d: %s (%d)\n", (int)pMethod->callCount, Sys_GetMethodDesc(pMethod), (int)(pMethod->totalTime/1000));
pMethod->callCount = 0;
}
printf("\n");
}
{
U32 numMethods, i;
I32 howMany = 25;
tMetaData *pCorLib;
// Report on most-used methods
pCorLib = CLIFile_GetMetaDataForAssembly("mscorlib");
numMethods = pCorLib->tables.numRows[MD_TABLE_METHODDEF];
printf("\nCorLib method execution time:\n");
for (; howMany > 0; howMany--) {
tMD_MethodDef *pMethod;
U64 maxTime = 0;
U32 maxIndex = 0;
for (i=1; i<=numMethods; i++) {
pMethod = (tMD_MethodDef*)MetaData_GetTableRow(pCorLib, MAKE_TABLE_INDEX(MD_TABLE_METHODDEF, i));
if (pMethod->totalTime > maxTime) {
maxTime = pMethod->totalTime;
maxIndex = i;
}
}
pMethod = (tMD_MethodDef*)MetaData_GetTableRow(pCorLib, MAKE_TABLE_INDEX(MD_TABLE_METHODDEF, maxIndex));
printf("%d: %s (%d)\n", (int)pMethod->callCount, Sys_GetMethodDesc(pMethod), (int)(pMethod->totalTime/1000));
pMethod->totalTime = 0;
}
printf("\n");
}
#endif
#ifdef DIAG_OPCODE_TIMES
{
I32 howMany = 25;
U32 i;
printf("\nOpCodes execution time:\n");
for (; howMany > 0; howMany--) {
U64 maxTime = 0;
U32 maxIndex = 0;
for (i=0; i<JIT_OPCODE_MAXNUM; i++) {
if (opcodeTimes[i] > maxTime) {
maxTime = opcodeTimes[i];
maxIndex = i;
}
}
printf("0x%03x: %dms (used %d times) (ave = %d)\n",
maxIndex, (int)(maxTime / 1000), (int)opcodeNumUses[maxIndex], (int)(maxTime / opcodeNumUses[maxIndex]));
opcodeTimes[maxIndex] = 0;
}
}
#endif
#ifdef DIAG_OPCODE_USE
{
I32 howMany = 25;
U32 i, j;
printf("\nOpcode use:\n");
for (j=1; howMany>0; howMany--, j++) {
U32 maxUse = 0;
U32 maxIndex = 0;
for (i=0; i<JIT_OPCODE_MAXNUM; i++) {
if (opcodeNumUses[i] > maxUse) {
maxUse = opcodeNumUses[i];
maxIndex = i;
}
}
printf("%02d 0x%03x: %d\n", j, maxIndex, maxUse);
opcodeNumUses[maxIndex] = 0;
}
}
#endif
//Crash("FINISHED!!!");
return retValue;
}