📄 timing.c
字号:
/* * Copyright (C) 1996-1998 by the Board of Trustees * of Leland Stanford Junior University. * * This file is part of the SimOS distribution. * See LICENSE file for terms of the license. * *//***************************************************************** * timing.c * * $Author: bosch $ * $Date: 1998/02/10 00:30:04 $ ****************************************************************/#include <stdio.h>#include <unistd.h>#include <sys/types.h>#include <string.h>#include <stdlib.h>#include <fcntl.h>#include <math.h>#include <setjmp.h>#include <ctype.h>#include <assert.h>#include "cpu_interface.h"#include "statrecord.h"#include "statistics.h"#include "simutil.h"#include "sim_error.h"#include "tcl_init.h"#include "stack.h"#define CPUMASK uint#define CPUNum ((CPUVec.CurrentCpuNum) ? CPUVec.CurrentCpuNum() : 0)/*#define TIMING_DEBUG*/typedef struct TimingTree TimingTree;typedef struct TimingThread TimingThread;typedef struct TimingNode TimingNode;struct TimingThread { char *name; Stack *stack; uint64 compStart; char active;};struct TimingTree { char *name; uint numThreads; Tcl_HashTable threads; TimingThread *currentThread[SIM_MAXCPUS]; StatRecordSwitch *selector; TimingNode *root;};struct TimingNode { char *name; Stats *stats; TimingNode *child; TimingNode *sibling; StatRecordBucket *bucket; char mutable;};static int CmdCreate(Tcl_Interp *interp, int argc, char *argv[]);static int CmdExit(Tcl_Interp *interp, int argc, char *argv[]);static int CmdDump(Tcl_Interp *interp, int argc, char *argv[]);static int CmdSwitch(Tcl_Interp *interp, int argc, char *argv[]);static int CmdTerminate(Tcl_Interp *interp, int argc, char *argv[]);static int CmdStart(Tcl_Interp *interp, int argc, char *argv[]);static int CmdVector(Tcl_Interp *interp, int argc, char *argv[]);static int CmdEnd(Tcl_Interp *interp, int argc, char *argv[]);static int CmdCurrent(Tcl_Interp *interp, int argc, char *argv[]);static int CmdStackList(Tcl_Interp *interp, int argc, char *argv[]);static int CmdFields(Tcl_Interp *interp, int argc, char *argv[]);static TimingTree *TreeCreate(char *TreeName);static TimingTree *TreeLookup(char *treeName);static void TreeDump(TimingTree *tree);static TimingThread *ThreadCreate(TimingTree *tree, char *threadName, char *startStates[], int numStartStates);static TimingThread *ThreadLookup(TimingTree *tree, char *threadName);static void ThreadExit(TimingTree *tree, TimingThread *thread);static int ThreadStartPhase(TimingTree *tree, TimingThread *thread, char *phaseName, int mutable);static void ThreadEndPhase(TimingTree *tree, TimingThread *thread, char *phaseName);static void TimingStackList(Stack *stack);static TimingNode *NodeCreate(char *name);static TimingNode *NodeFind(TimingNode *parent, char *name);static void NodeZip(TimingTree *tree, TimingNode *src, TimingNode *dest);static void OverflowDebug(Tcl_Interp *interp, TimingThread *thread);static Tcl_HashTable trees;static tclcmd timingCmds[] = {{ "create", 3, CmdCreate, " create treeName"},{ "exit", 3, CmdExit, " exit treeName"},{ "dump", 3, CmdDump, " dump treeName"},{ "switch", -1, CmdSwitch, " switch treeName threadName ?phase ...?"},{ "terminate", 4, CmdTerminate, " terminate treeName threadName"},{ "start", -1, CmdStart, " start treeName phaseName ?threadName?"},{ "start?", -1, CmdStart, " start? treeName phaseName ?threadName?"},{ "vector", -1, CmdVector, " vector treeName phaseName ?threadName?"},{ "end", -1, CmdEnd, " end treeName phaseName ?threadName?"},{ "current", -1, CmdCurrent, " current treeName ?threadName?"},{ "dumpstack", -1, CmdStackList, " dumpstack treeName ?threadName?"},{ "fields", 2, CmdFields, " fields"},{ NULL, 0, NULL, NULL}};/**************************************************************** * TimingInit ****************************************************************/void TimingInit(Tcl_Interp *interp){ Tcl_InitHashTable(&trees, TCL_STRING_KEYS); Tcl_CreateCommand(interp, "timing", DispatchCmd, (ClientData)timingCmds, NULL);}/***************************************************************** * CmdCreate * * Create a new timing tree. This will be the level at which you * limit timing to certain pid's. ****************************************************************/static int CmdCreate(Tcl_Interp *interp, int argc, char *argv[]){ char *treeName = argv[2]; if (TreeCreate(treeName) == NULL) { Tcl_AppendResult(interp, "tree name already taken \"", treeName, "\"", NULL); return TCL_ERROR; } return TCL_OK;}/***************************************************************** * CmdExit * * Assorted cleanup routines to get all of the timing stuff in order * before printing. *****************************************************************/static int CmdExit(Tcl_Interp *interp, int argc, char *argv[]){ Tcl_HashEntry *entry; Tcl_HashSearch search; TimingTree *tree; char *treeName; treeName = argv[2]; if ((tree = TreeLookup(treeName)) == NULL) { Tcl_AppendResult(interp, "no tree named \"", treeName, "\"", NULL); return TCL_ERROR; } for (entry = Tcl_FirstHashEntry(&tree->threads, &search); entry; entry = Tcl_NextHashEntry(&search)) { ThreadExit(tree, (TimingThread *)Tcl_GetHashValue(entry)); } return TCL_OK;}/***************************************************************** * CmdStart * * Entry point to a new phase... add it if it doesn't exist yet. * This is a "push". ****************************************************************/static int CmdStart(Tcl_Interp *interp, int argc, char *argv[]){ TimingTree *tree; TimingThread *thread; char *treeName; char *phaseName; if ((argc != 4) && (argc != 5)) { Tcl_AppendResult(interp, "wrong number of arguments", NULL); return TCL_ERROR; } treeName = argv[2]; phaseName = argv[3]; if ((tree = TreeLookup(treeName)) == NULL) { Tcl_AppendResult(interp, "no tree named \"", treeName, "\"", NULL); return TCL_ERROR; } if (argc == 5) { thread = ThreadLookup(tree, argv[4]); if (!thread) { CPUWarning("TIMING: no thread named %s\n", argv[4]); return TCL_OK; } } else { thread = tree->currentThread[CPUNum]; if (!thread) { Tcl_AppendResult(interp, "no current thread in \"", treeName, "\"", NULL); return TCL_ERROR; } } if (StackEmpty(thread->stack)) { Tcl_AppendResult(interp, "cannot start phase on terminated thread", NULL); return TCL_ERROR; } if (thread->active) { if (ThreadStartPhase(tree, thread, phaseName, argv[1][5]) != TCL_OK) { OverflowDebug(interp, thread); return TCL_ERROR; } } else { ThreadEndPhase(tree, thread, "DESCHED"); if (ThreadStartPhase(tree, thread, phaseName, argv[1][5]) != TCL_OK) { OverflowDebug(interp, thread); return TCL_ERROR; } if (ThreadStartPhase(tree, thread, "DESCHED", 0) != TCL_OK) { OverflowDebug(interp, thread); return TCL_ERROR; } }#ifdef TIMING_DEBUG CPUPrint("TIMING: Start thread %s\n", thread->name); TimingStackList(thread->stack);#endif return TCL_OK;}/***************************************************************** * CmdVector ****************************************************************/static int CmdVector(Tcl_Interp *interp, int argc, char *argv[]){ TimingTree *tree; TimingThread *thread; TimingNode *node; char *treeName; char *phaseName; if ((argc != 4) && (argc != 5)) { Tcl_AppendResult(interp, "wrong number of arguments", NULL); return TCL_ERROR; } treeName = argv[2]; phaseName = argv[3]; if ((tree = TreeLookup(treeName)) == NULL) { Tcl_AppendResult(interp, "no tree named \"", treeName, "\"", NULL); return TCL_ERROR; } if (argc == 5) { thread = ThreadLookup(tree, argv[4]); if (!thread) { CPUWarning("TIMING: no thread named %s\n", argv[4]); return TCL_OK; } } else { thread = tree->currentThread[CPUNum]; if (!thread) { Tcl_AppendResult(interp, "no current thread in \"", treeName, "\"", NULL); return TCL_ERROR; } } if (StackEmpty(thread->stack)) { Tcl_AppendResult(interp, "cannot vector phase on terminated thread", NULL); return TCL_ERROR; } if (thread->active) { node = UINT64_TO_PTR(StackIndex(thread->stack, 2)); } else { node = UINT64_TO_PTR(StackIndex(thread->stack, 5)); } ASSERT(node); if (!node->mutable) { CPUWarning("TIMING: CPU %d CYCLE %lld: node not mutable, tree: %s, node: %s\n", CPUNum, CPUVec.CycleCount(CPUNum), treeName, node->name); TimingStackList(thread->stack); return TCL_OK; } ASSERT(!node->sibling); free(node->name); node->name = SaveString(phaseName); return TCL_OK;}/***************************************************************** * CmdEnd * * End of an existing phase. Print a warning if this ending phase * doesn't match the top of the stack. ****************************************************************/static int CmdEnd(Tcl_Interp *interp, int argc, char *argv[]){ char *treeName; char *phaseName; TimingTree *tree; TimingThread *thread; if ((argc != 4) && (argc != 5)) { Tcl_AppendResult(interp, "wrong number of arguments", NULL); return TCL_ERROR; } treeName = argv[2]; phaseName = argv[3]; if ((tree = TreeLookup(treeName)) == NULL) { Tcl_AppendResult(interp, "no tree named \"", treeName, "\"", NULL); return TCL_ERROR; } if (argc == 5) { thread = ThreadLookup(tree, argv[4]); if (!thread) { CPUWarning("TIMING: no thread named %s\n", argv[4]); return TCL_OK; } } else { thread = tree->currentThread[CPUNum]; if (!thread) { Tcl_AppendResult(interp, "no current thread in \"", treeName, "\"", NULL); return TCL_ERROR; } } if (StackEmpty(thread->stack)) { Tcl_AppendResult(interp, "cannot end phase on terminated thread", NULL); return TCL_ERROR; } if (thread->active) { ThreadEndPhase(tree, thread, phaseName); } else { ThreadEndPhase(tree, thread, "DESCHED"); ThreadEndPhase(tree, thread, phaseName); ThreadStartPhase(tree, thread, "DESCHED", 0); }#ifdef TIMING_DEBUG CPUPrint("TIMING: End thread %s\n", thread->name); TimingStackList(thread->stack);#endif return TCL_OK;}/***************************************************************** * CmdCurrent * * Return the top phase on the stack ****************************************************************/static intCmdCurrent(Tcl_Interp *interp, int argc, char *argv[]){ TimingTree *tree; TimingThread *thread; TimingNode *node; char *treeName; if (argc !=3 && argc !=4) { Tcl_AppendResult(interp,"wrong number of arguments",NULL); return TCL_ERROR; } treeName = argv[2]; if ((tree = TreeLookup(treeName)) == NULL) { Tcl_AppendResult(interp, "no tree named \"", treeName, "\"", NULL); return TCL_ERROR; } if (argc == 4) { if (!(thread = ThreadLookup(tree, argv[3]))) { Tcl_AppendResult(interp, "no thread named \"", argv[3], "\"", NULL); return TCL_ERROR; } } else { if (!(thread = tree->currentThread[CPUNum])) { Tcl_AppendResult(interp, "no current thread", NULL); return TCL_ERROR; } ASSERT(thread->active); } if (StackEmpty(thread->stack)) { Tcl_AppendResult(interp, "cannot get current phase on terminated thread", NULL); return TCL_ERROR; } if (thread->active) { node = UINT64_TO_PTR(StackIndex(thread->stack, 2)); } else { node = UINT64_TO_PTR(StackIndex(thread->stack, 5)); } if (node) { ASSERT(node->name); Tcl_AppendResult(interp, node->name, NULL); } else { Tcl_AppendResult(interp, "", NULL); } return TCL_OK;}/***************************************************************** * CmdStackList * * Access from TCL to stacklist debugging command ****************************************************************/static intCmdStackList(Tcl_Interp *interp, int argc, char *argv[]){ TimingTree *tree; TimingThread *thread; char *treeName; if (argc !=3 && argc !=4) { Tcl_AppendResult(interp,"wrong number of arguments",NULL); return TCL_ERROR; } treeName = argv[2]; if ((tree = TreeLookup(treeName)) == NULL) { Tcl_AppendResult(interp, "no tree named \"", treeName, "\"", NULL); return TCL_ERROR; } if (argc == 4) { if (!(thread = ThreadLookup(tree, argv[3]))) { Tcl_AppendResult(interp, "no thread named \"", argv[3], "\"", NULL); return TCL_ERROR; } } else { if (!(thread = tree->currentThread[CPUNum])) { Tcl_AppendResult(interp, "no current thread", NULL); return TCL_ERROR; } } TimingStackList(thread->stack); return TCL_OK;}/***************************************************************** * CmdSwitch * * Move to another thread... create a stack for it if it doesn't * exist. ****************************************************************/static int CmdSwitch(Tcl_Interp *interp, int argc, char *argv[]){ TimingTree *tree; TimingThread *thread; char *treeName; char *threadName; char **startState; int numStartStates; if ((argc < 4)) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], timingCmds[3].usage, "\"", NULL); return TCL_ERROR; } treeName = argv[2]; threadName = argv[3]; startState = &(argv[4]); numStartStates = argc - 4; if ((tree = TreeLookup(treeName)) == NULL) { Tcl_AppendResult(interp, "no tree named \"", treeName, "\"", NULL); return TCL_ERROR; } /* First, if this thread has not yet exited, then push DESCHED */ thread = tree->currentThread[CPUNum]; if (thread && !StackEmpty(thread->stack)) { if (ThreadStartPhase(tree, thread, "DESCHED", 0) != TCL_OK) { OverflowDebug(interp, thread); return TCL_ERROR; } } if (thread) { thread->active = 0; } /* See if a stack for new thread exists... if not, create one */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -