From 831d6f8a0233c819f8374f9ba6b4941ec3922e73 Mon Sep 17 00:00:00 2001 From: Patrick Lu Date: Mon, 18 Dec 2017 06:40:58 -0700 Subject: Initial release of jitter micro Change-Id: I69bc52ddafe2be1f549f0652ab24fb316ee159c5 Signed-off-by: Patrick Lu --- README | 12 +++ jitter/Makefile | 19 ++++ jitter/jitter.c | 303 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 334 insertions(+) create mode 100644 README create mode 100644 jitter/Makefile create mode 100644 jitter/jitter.c diff --git a/README b/README new file mode 100644 index 0000000..33f4993 --- /dev/null +++ b/README @@ -0,0 +1,12 @@ +------------------------------------------------------- +Performance Measurement and Analysis Tools (pma_tools) +------------------------------------------------------- + +pma_tools will provide several useful scripts, micro-benchmarks to help +characterize data plane performance. + +------------------------------------------------------- +micro-benchmarks +------------------------------------------------------- + +- jitter : A user space C program to assess OS level overhead. diff --git a/jitter/Makefile b/jitter/Makefile new file mode 100644 index 0000000..547d57f --- /dev/null +++ b/jitter/Makefile @@ -0,0 +1,19 @@ +# Copyright (c) 2017 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +all: + gcc -O1 jitter.c -fstack-protector-all -fPIC -Wformat -Wformat-security -Wl,-z,noexecstack,-z,relro,-z,now -o jitter + +clean: + rm -f jitter diff --git a/jitter/jitter.c b/jitter/jitter.c new file mode 100644 index 0000000..07cd066 --- /dev/null +++ b/jitter/jitter.c @@ -0,0 +1,303 @@ +/** + * Copyright (c) 2017 Intel Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Original Creation Date : Sept 1, 2012 + * Last Modified : Dec 17, 2017 + * Author: Shrikant M. Shah + * Contributor: Patrick Lu + * + * Program for measuring software jitter + * + * This program is meant for measuring the "jitter" in the execution time caused by OS and/or the underlying architecture. + * The program does the following: + * - Calls a dummy function which consists of a small piece of code block being executed in a loop. The loop count is user defined (default 80,000). + * - Measures the Execution time for this function in Core cycles + * - Compares the Execution time with Instantaneous Minimum and Maximum execution time values tracked during the display update interval. These values are adjusted based on the comparison. + * - Compares the execution time with Absolute Minimum and maximum execution values since the program started. These values are adjusted based on the comparison. + * - Repeats above operation. + * - Updates the display with the statistics once after the dummy function is executed certain number of times (default 20,000). + * The display update interval is approximately set to 1 second. At this time, Instantaneous Minimum and Maximum execution time are initialized. + * - The statistics include Instantaneous Minimum and Maximum execution times measured during the display interval and jitter. + * The most important statistic to watch is Inst_jitter, the difference between instantaneous Minimum and Maximum execution times + * Display update interval is also user programmable. + * Note that Absolute Minimum and Maximum execution times keep track of variations in the execution time over a long period of time. + * The Absolute Min and Max values can be reset using User signal. + * + */ + +#include +#include +#include +#include +#include +#include + +union timestampclock +{ + uint64_t timestamp64; + struct + { + uint32_t low; + uint32_t high; + }; +}a; + +#define MINVAL 0xfffffffL + +int resetStats=0; +unsigned int loopcount = 80000; +unsigned int displayUpdate = 20000; +#ifdef PROCESSOR_TRACE +unsigned int jitter_threshold = 15000; +#endif +unsigned int iterations = 200; + +char *title = " Inst_Min Inst_Max Inst_jitter last_Exec Abs_min Abs_max tmp Interval Sample No\n"; + +int dummyop(unsigned int loops, unsigned startval) +{ + register unsigned int i,a , k; + a = startval ; + k = loops; + for(i=0; i < k; i++) + { + a += (3*i + k); + a &=0x7f0f0000; + } + + return a; +} + +inline uint64_t TimeStampCounter() +{ + union timestampclock tscount; + uint32_t eax,edx; + + __asm__ volatile("mfence"); + + __asm__ __volatile__("rdtsc" : "=a" (eax), "=d" (edx)); + tscount.low = eax; + tscount.high = edx; + return tscount.timestamp64; +} + +inline uint64_t TimeStampCounterEnd() +{ + union timestampclock tscount; + uint32_t eax,edx; + + __asm__ __volatile__("rdtscp" : "=a" (eax), "=d" (edx)::"%rcx"); + tscount.low = eax; + tscount.high = edx; + __asm__ __volatile__("rdtscp" : "=a" (eax), "=d" (edx)::"%rcx"); + return tscount.timestamp64; +} + +uint64_t clockdiff(uint64_t starttime,uint64_t endtime) +{ + + uint64_t a ; + if (starttime > endtime) + a = starttime - endtime; + else + a = endtime - starttime; + + return a ; +} + +void signalHandler(int signalno) +{ + if (signalno == SIGUSR1) + { + printf("Resettings Absolute Min and Max counts\n"); + resetStats = 1; + } +} + +void showhelp() +{ + printf("usage:\n"); + printf("taskset -c ./jitter [-l] [r] [-h] [-p $(pgrep perf)] [-t]\n"); + + printf(" -r : Display update rate. Default is %d\n", displayUpdate); + printf(" -l : Loop count for code block. Default is %d\n", loopcount); + printf(" -p : perf_pid [run: perf record -S -C$CORENO -e intel_pt// -v on another window]\n"); +#ifdef PROCESSOR_TRACE + printf(" -t : jitter threshold for perf trigger. Default is > %d cycles\n", jitter_threshold); +#endif + printf(" -i : Sample counts after which program terminates. Default count is %u\n", iterations); + printf("For resetting statistics use: pkill -USR1 jitter\n"); + printf("For elevating the priority of this program try: chrt -r -p 99 processId\n"); + +} + +void displayInfo() +{ + printf("Timings are in CPU Core cycles\n"); + printf("Inst_Min: Minimum Excution time during the display update interval(default is ~1 second)\n"); + printf("Inst_Max: Maximum Excution time during the display update interval(default is ~1 second)\n"); + printf("Inst_jitter: Jitter in the Excution time during rhe display update interval. This is the value of interest\n"); + printf("last_Exec: The Excution time of last iteration just before the display update\n"); + printf("Abs_Min: Absolute Minimum Excution time since the program started or statistics were reset\n"); + printf("Abs_Max: Absolute Maximum Excution time since the program started or statistics were reset\n"); + printf("tmp: Cumulative value calcualted by the dummy function\n"); + printf("Interval: Time interval between the display updates in Core Cycles\n"); + printf("Sample No: Sample number\n\n"); +} + +int main(int argc, char* argv[]) +{ + + register unsigned int tref=0; + register unsigned int SampleNo=0; + register long currentExectime; + uint64_t startTime,endTime,seedtime, lasttime; + uint64_t absoluteMin=MINVAL, absoluteMax=0, TransientMax=0, TransientMin=MINVAL; + unsigned int tmp=0; + int userinput; +#ifdef PROCESSOR_TRACE + pid_t perf_pid = -1; + int skip = 5, signaled = 0; +#endif + + printf("Linux Jitter testing program version 1.8\n"); + + while ((userinput = getopt(argc, argv, "l:r:hp:t:i:")) != EOF) + { + switch(userinput) + { + case 'h' : showhelp(); + exit(0); + case 'l' : loopcount = strtoul(optarg, (char**)NULL, 0); + break; + case 'r' : displayUpdate = strtoul(optarg, (char**)NULL, 0); + break; + case 'p' : +#ifdef PROCESSOR_TRACE + perf_pid = strtol(optarg, (char**)NULL, 0); + printf("Perf PID=%d\n", perf_pid); +#else + printf("jitter program did not compile with -DPROCESSOR_TRACE, cannot use Linux perf with Intel Processor Trace to record jitter source\n"); +#endif + break; + + case 'i' : + iterations = strtoul(optarg, (char**)NULL, 0); + printf("Iterations=%u\n", iterations); + break; + + case 't' : +#ifdef PROCESSOR_TRACE + jitter_threshold = strtoul(optarg, (char**)NULL, 0); + printf("Update jitter threshold to %u\n", jitter_threshold); +#else + printf("jitter program did not compile with -DPROCESSOR_TRACE, cannot use Linux perf with Intel Processor Trace to record jitter source\n"); +#endif + break; + } + } + + printf("The pragram will execute a dummy function %u times\n",loopcount); + printf("Display is updated every %u displayUpdate intervals\n",displayUpdate); + + displayInfo(); + + // register signal handler for resetting Absoulte statistics + if (signal(SIGUSR1, signalHandler) == SIG_ERR) + { + printf("**** Error: Signal Handler is somehow not registered. Sorry, you cannot reset statistics using USR1 signal\n"); + + } + + printf("%s",title); + + seedtime = TimeStampCounter(); // get a random value from timestamp + + // prime the cache by executing the code a few times + for(SampleNo =0;SampleNo < 1000; SampleNo++) + { + tmp += dummyop(loopcount, (uint32_t) seedtime); + } + + SampleNo = 0; + tref =0; + + do // run the loop for a long time + { + + startTime = TimeStampCounter(); // timestamp start + tmp += dummyop(loopcount, (uint32_t) seedtime); // run the compute function 'loopcount' times + endTime = TimeStampCounterEnd(); // timestamp end + + currentExectime = clockdiff(startTime, endTime); // calculate differnce in clocks + + // calcualte absolute min and max + if (currentExectime < absoluteMin) // calculate absolute min + absoluteMin = currentExectime; + if (currentExectime>= absoluteMax) // calculate absolute max + absoluteMax = currentExectime; + + // calcualte Max execution time within the Display displayUpdate interval + if (currentExectime < TransientMin) + TransientMin = currentExectime; // temporary min + if (currentExectime >= TransientMax) + TransientMax = currentExectime; // temporary max + +#ifdef PROCESSOR_TRACE + if ((perf_pid != -1) && (SampleNo > skip) && !(signaled) && (currentExectime - TransientMin) > jitter_threshold) { + kill(perf_pid, SIGUSR2); + signaled = 1; + } +#endif + + if(tref++ >= displayUpdate) // update the stats on screen/memory at displayUpdate interval + { + tref=1; + if(SampleNo > 0) + printf("%10lu %10lu %10lu %10lu %10lu %10lu %13u %10lu %10u\n", + TransientMin, + TransientMax, + TransientMax-TransientMin, + currentExectime, absoluteMin, + absoluteMax,tmp, + (endTime-lasttime), + SampleNo); + + SampleNo++; + lasttime = endTime; + + TransientMax = 0; // reset TransientMax to zero + TransientMin = MINVAL; + + if (resetStats !=0) // the varibale is set if user issues 'pkill USR1 jitter' signal + { + absoluteMax = 0; + absoluteMin = MINVAL; + resetStats = 0; + SampleNo = 1 ; +#ifdef PROCESSOR_TRACE + signaled = 0; +#endif + } + + + if (!(SampleNo % 40)) // print the title every 40 lines + printf("%s",title); + + } + + } while(SampleNo <= iterations); + +} -- cgit 1.2.3-korg