diff options
Diffstat (limited to 'jittertest')
-rw-r--r-- | jittertest/COPYING | 340 | ||||
-rw-r--r-- | jittertest/JitterTest.c | 1044 | ||||
-rw-r--r-- | jittertest/Makefile | 46 | ||||
-rw-r--r-- | jittertest/README | 197 | ||||
-rw-r--r-- | jittertest/filljffs2.sh | 16 | ||||
-rw-r--r-- | jittertest/plotJittervsFill.c | 312 |
6 files changed, 1955 insertions, 0 deletions
diff --git a/jittertest/COPYING b/jittertest/COPYING new file mode 100644 index 0000000..60549be --- /dev/null +++ b/jittertest/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/jittertest/JitterTest.c b/jittertest/JitterTest.c new file mode 100644 index 0000000..13c64d9 --- /dev/null +++ b/jittertest/JitterTest.c @@ -0,0 +1,1044 @@ +/*********************************************************************** + * + * Copyright: Daniel Measurement and Control, Inc. + * 9753 Pine Lake Drive + * Houston, TX 77055 + * + * Created by: Vipin Malik and Gail Murray + * Released under GPL by permission of Daniel Industries. + * + * This software is licensed under the GPL version 2. Plese see the file + * COPYING for details on the license. + * + * NO WARRANTY: Absolutely no claims of warranty or fitness of purpose + * are made in this software. Please use at your own risk. + * + * Filename: JitterTest.c + * + * Description: Program to be used to measure wake jitter. + * See README file for more info. + * + * + * Revision History: + * $Id: JitterTest.c,v 1.13 2005/11/07 11:15:20 gleixner Exp $ + * $Log: JitterTest.c,v $ + * Revision 1.13 2005/11/07 11:15:20 gleixner + * [MTD / JFFS2] Clean up trailing white spaces + * + * Revision 1.12 2001/08/10 19:23:11 vipin + * Ready to be released under GPL! Added proper headers etc. + * + * Revision 1.11 2001/07/09 15:35:50 vipin + * Couple of new features:1. The program runs by default as a "regular" + * (SCHED_OTHER) task by default, unless the -p n cmd line parameter is + * specified. It then runs as SCHED_RR at that priority. + * 2. Added ability to send SIGSTOP/SIGCONT to a specified PID. This + * would presumably be the PID of the JFFS2 GC task. SIGSTOP is sent + * before writing to the fs, and a SIGCONT after the write is done. + * 3. The "pad" data now written to the file on the "fs under test" is + * random, not sequential as previously. + * + * Revision 1.10 2001/06/27 19:14:24 vipin + * Now console file to log at can be specified from cmd line. This can enable + * you to run two instances of the program- one logging to the /dev/console + * and another to a regular file (if you want the data) or /dev/null if you don't. + * + * Revision 1.9 2001/06/25 20:21:31 vipin + * This is the latest version, NOT the one last checked in! + * + * Revision 1.7 2001/06/18 22:36:19 vipin + * Fix minor typo that excluded '\n' from msg on console. + * + * Revision 1.6 2001/06/18 21:17:50 vipin + * Added option to specify the amount of data written to outfile each period. + * The regular info is written, but is then padded to the requested size. + * This will enable testing of different sized writes to JFFS fs. + * + * Revision 1.5 2001/06/08 19:36:23 vipin + * All write() are now checked for return err code. + * + * Revision 1.4 2001/06/06 23:10:31 vipin + * Added README file. + * In JitterTest.c: Changed operation of periodic timer to one shot. The timer is now + * reset when the task wakes. This way every "jitter" is from the last time and + * jitters from previous times are not accumulated and screw aroud with our display. + * + * All jitter is now +ve. (as it should be). Also added a "read file" functionality + * to test for jitter in task if we have to read from JFFS fs. + * The program now also prints data to console- where it can be logged, interspersed with + * other "interesting" printk's from the kernel and drivers (flash sector erases etc.) + * + * Revision 1.3 2001/03/01 19:20:39 gmurray + * Add priority scheduling. Shortened name of default output file. + * Changed default interrupt period. Output delta time and jitter + * instead of time of day. + * + * Revision 1.2 2001/02/28 16:20:19 vipin + * Added version control Id and log fields. + * + ***********************************************************************/ +/*************************** Included Files ***************************/ +#include <stdio.h> /* fopen, printf, fprintf, fclose */ +#include <string.h> /* strcpy, strcmp */ +#include <stdlib.h> /* exit, atol, atoi */ +#include <sys/time.h> /* setitimer, settimeofday, gettimeofday */ +#include <signal.h> /* signal */ +#include <sched.h> /* sched_setscheduler, sched_get_priority_min,*/ +/* sched_get_priority_max */ +#include <unistd.h> /* gettimeofday, sleep */ +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/mman.h> + + + +/**************************** Enumerations ****************************/ +enum timerActions + { + ONESHOT, + AUTORESETTING + }; + + + +/****************************** Constants *****************************/ +/* Exit error codes */ +#define EXIT_FILE_OPEN_ERR (1) /* error opening output file*/ +#define EXIT_REG_SIGALRM_ERR (2) /* error registering SIGALRM*/ +#define EXIT_REG_SIGINT_ERR (3) /* error registering SIGINT */ +#define EXIT_INV_INT_PERIOD (4) /* error invalid int. period*/ +#define EXIT_MIN_PRIORITY_ERR (5) /* error, minimum priority */ +#define EXIT_MAX_PRIORITY_ERR (6) /* error, maximum priority */ +#define EXIT_INV_SCHED_PRIORITY (7) /* error, invalid priority */ +#define EXIT_SET_SCHEDULER_ERR (8) /* error, set scheduler */ +#define EXIT_PREV_TIME_OF_DAY_ERR (9) /* error, init. prev. */ +/* time of day */ + +#define MAX_FILE_NAME_LEN (32) /* maximum file name length */ + +#define STRINGS_EQUAL ((int) 0) /* strcmp value if equal */ + +#define MIN_INT_PERIOD_MILLISEC ( 5L) /* minimum interrupt period */ +#define MAX_INT_PERIOD_MILLISEC (5000L) /* maximum interrupt period */ +#define DEF_INT_PERIOD_MILLISEC ( 10L) /* default interrupt period */ + +#define READ_FILE_MESSAGE "This is a junk file. Must contain at least 1 byte though!\n" + +/* The user can specify that the program pad out the write file to + a given number of bytes. But a minimum number needs to be written. This + will contain the jitter info. +*/ +#define MIN_WRITE_BYTES 30 +#define DEFAULT_WRITE_BYTES 30 +#define MAX_WRITE_BYTES 4096 + +/* used for gen a printable ascii random # between spc and '~' */ +#define MIN_ASCII 32 /* <SPACE> can be char*/ +#define MAX_ASCII 126.0 /* needs to be float. See man rand() */ + +/*---------------------------------------------------------------------- + * It appears that the preprocessor can't handle multi-line #if + * statements. Thus, the check on the default is divided into two + * #if statements. + *---------------------------------------------------------------------*/ +#if (DEF_INT_PERIOD_MILLISEC < MIN_INT_PERIOD_MILLISEC) +#error *** Invalid default interrupt period. *** +#endif + +#if (DEF_INT_PERIOD_MILLISEC > MAX_INT_PERIOD_MILLISEC) +#error *** Invalid default interrupt period. *** +#endif + + +#define TRUE 1 /* Boolean true value */ +#define FALSE 0 + +/* Time conversion constants. */ +#define MILLISEC_PER_SEC (1000L) /* milliseconds per second */ +#define MICROSEC_PER_MILLISEC (1000L) /* microsecs per millisec */ +#define MICROSEC_PER_SEC (1000000L) /* microsecs per second */ + +#define PRIORITY_POLICY ((int) SCHED_RR) /* If specified iwth "-p" */ + + + +/************************** Module Variables **************************/ +/* version identifier (value supplied by CVS)*/ +static const char Version[] = "$Id: JitterTest.c,v 1.13 2005/11/07 11:15:20 gleixner Exp $"; + +static char OutFileName[MAX_FILE_NAME_LEN+1]; /* output file name */ +static char LogFile[MAX_FILE_NAME_LEN+1] = "/dev/console"; /* default */ +static char ReadFile[MAX_FILE_NAME_LEN+1]; /* This file is read. Should + contain at least 1 byte */ + +static int WriteBytes = DEFAULT_WRITE_BYTES; /* pad out file to these many bytes. */ +static int Fd1; /* fd where the above buffer if o/p */ +static int Cfd; /* fd to console (or file specified) */ +static int Fd2; /* fd for the ReadFile */ +static int DoRead = FALSE; /* should we attempt to ReadFile?*/ +static long InterruptPeriodMilliSec; /* interrupt period, millisec */ +static int MinPriority; /* minimum scheduler priority */ +static int MaxPriority; /* maximum scheduler priority */ +static int RequestedPriority; /* requested priority */ +static struct itimerval ITimer; /* interrupt timer structure */ +static struct timeval PrevTimeVal; /* previous time structure */ +static struct timeval CurrTimeVal; /* current time structure */ +static long LastMaxDiff = 0; /* keeps track of worst jitter encountered */ + +static int GrabKProfile = FALSE; /* To help determine system bottle necks + this parameter can be set. This causes + the /proc/profile file to be read and + stored in unique filenames in current + dir, and indication to be o/p on the + /dev/console also. + */ +static long ProfileTriggerMSecs = 15000l; /* Jitter time in seconds that triggers + a snapshot of the profile to be taken + + */ +static int SignalGCTask = FALSE; /* should be signal SIGSTOP/SIGCONT to gc task?*/ +static int GCTaskPID; + +static int RunAsRTTask = FALSE; /* default action unless priority is + specified on cmd line */ + + +/********************* Local Function Prototypes **********************/ +void HandleCmdLineArgs(int argc, char *argv[]); +void SetFileName(char * pFileName); +void SetInterruptPeriod(char * pASCIIInterruptPeriodMilliSec); +void SetSchedulerPriority(char * pASCIISchedulerPriority); + +void PrintVersionInfo(void); +void PrintHelpInfo(void); + +int Write(int fd, void *buf, size_t bytes, int lineNo); + +void InitITimer(struct itimerval * pITimer, int action); + +/* For catching timer interrupts (SIGALRM). */ +void AlarmHandler(int sigNum); + +/* For catching Ctrl+C SIGINT. */ +void SignalHandler(int sigNum); + + + +/*********************************************************************** + * main function + * return: exit code + ***********************************************************************/ +int main( + int argc, + char *argv[]) +{ + struct sched_param schedParam; + + int mypri; + char tmpBuf[200]; + + + strcpy(OutFileName,"jitter.dat"); + InterruptPeriodMilliSec = MIN_INT_PERIOD_MILLISEC; + + /* Get the minimum and maximum priorities. */ + MinPriority = sched_get_priority_min(PRIORITY_POLICY); + MaxPriority = sched_get_priority_max(PRIORITY_POLICY); + if (MinPriority == -1) { + printf("\n*** Unable to get minimum priority. ***\n"); + exit(EXIT_MIN_PRIORITY_ERR); + } + if (MaxPriority == -1) { + printf("\n*** Unable to get maximum priority. ***\n"); + exit(EXIT_MAX_PRIORITY_ERR); + } + + /* Set requested priority to minimum value as default. */ + RequestedPriority = MinPriority; + + HandleCmdLineArgs(argc, argv); + + if(mlockall(MCL_CURRENT|MCL_FUTURE) < 0){ + printf("Could not lock task into memory. Bye\n"); + perror("Error"); + } + + if(RunAsRTTask){ + + /* Set the priority. */ + schedParam.sched_priority = RequestedPriority; + if (sched_setscheduler( + 0, + PRIORITY_POLICY, + &schedParam) != (int) 0) { + printf("Exiting: Unsuccessful sched_setscheduler.\n"); + close(Fd1); + exit(EXIT_SET_SCHEDULER_ERR); + } + + + /* Double check as I have some doubts that it's really + running at realtime priority! */ + if((mypri = sched_getscheduler(0)) != RequestedPriority) + { + printf("Not running with request priority %i. running with priority %i instead!\n", + RequestedPriority, mypri); + }else + { + printf("Running with %i priority. Good!\n", mypri); + } + + } + + /*------------------------- Initializations --------------------------*/ + if((Fd1 = open(OutFileName, O_RDWR|O_CREAT|O_SYNC)) <= 0) + { + perror("Cannot open outfile for write:"); + exit(1); + } + + /* If a request is made to read from a specified file, then create that + file and fill with junk data so that there is something there to read. + */ + if(DoRead) + { + + if((Fd2 = open(ReadFile, O_RDWR|O_CREAT|O_SYNC|O_TRUNC)) <= 0) + { + perror("cannot open read file:"); + exit(1); + }else + { + + /* Don't really care how much we write here */ + if(write(Fd2, READ_FILE_MESSAGE, strlen(READ_FILE_MESSAGE)) < 0) + { + perror("Problems writing to readfile:"); + exit(1); + } + lseek(Fd2, 0, SEEK_SET); /* position back to byte #0 */ + } + } + + + + /* Also log output to console. This way we can capture it + on a serial console to a log file. + */ + if((Cfd = open(LogFile, O_WRONLY|O_SYNC)) <= 0) + { + perror("cannot open o/p logfile:"); + exit(1); + } + + + /* Set-up handler for periodic interrupt. */ + if (signal(SIGALRM, &AlarmHandler) == SIG_ERR) { + printf("Couldn't register signal handler for SIGALRM.\n"); + sprintf(tmpBuf, + "Couldn't register signal handler for SIGALRM.\n"); + Write(Fd1, tmpBuf, strlen(tmpBuf), __LINE__); + + close(Fd1); + exit(EXIT_REG_SIGALRM_ERR); + } + + /* Set-up handler for Ctrl+C to exit the program. */ + if (signal(SIGINT, &SignalHandler) == SIG_ERR) { + printf("Couldn't register signal handler for SIGINT.\n"); + sprintf(tmpBuf, + "Couldn't register signal handler for SIGINT.\n"); + Write(Fd1, tmpBuf, strlen(tmpBuf), __LINE__); + + close(Fd1); + exit(EXIT_REG_SIGINT_ERR); + } + + printf("Press Ctrl+C to exit the program.\n"); + printf("Output File: %s\n", OutFileName); + printf("Scheduler priority: %d\n", RequestedPriority); + sprintf(tmpBuf, "\nScheduler priority: %d\n", + RequestedPriority); + Write(Fd1, tmpBuf, strlen(tmpBuf), __LINE__); + + Write(Cfd, tmpBuf, strlen(tmpBuf), __LINE__); + + printf("Interrupt period: %ld milliseconds\n", + InterruptPeriodMilliSec); + sprintf(tmpBuf, "Interrupt period: %ld milliseconds\n", + InterruptPeriodMilliSec); + + Write(Fd1, tmpBuf, strlen(tmpBuf), __LINE__); + + Write(Cfd, tmpBuf, strlen(tmpBuf), __LINE__); + + + fflush(0); + + + + /* Initialize the periodic timer. */ + InitITimer(&ITimer, ONESHOT); + + /* Initialize "previous" time. */ + if (gettimeofday(&PrevTimeVal, NULL) != (int) 0) { + printf("Exiting - "); + printf("Unable to initialize previous time of day.\n"); + sprintf(tmpBuf, "Exiting - "); + Write(Fd1, tmpBuf, strlen(tmpBuf), __LINE__); + + sprintf(tmpBuf, + "Unable to initialize previous time of day.\n"); + + Write(Fd1, tmpBuf, strlen(tmpBuf), __LINE__); + + } + + /* Start the periodic timer. */ + setitimer(ITIMER_REAL, &ITimer, NULL); + + + while(TRUE) { /* Intentional infinite loop. */ + /* Sleep for one second. */ + sleep((unsigned int) 1); + } + + /* Just in case. File should be closed in SignalHandler. */ + close(Fd1); + close(Cfd); + + return 0; +} + + + + +/*********************************************************************** + * SignalHandler + * This is a handler for the SIGINT signal. It is assumed that the + * SIGINT is due to the user pressing Ctrl+C to halt the program. + * output: N/A + ***********************************************************************/ +void SignalHandler( + int sigNum) +{ + + char tmpBuf[200]; + + /* Note sigNum not used. */ + printf("Ctrl+C detected. Worst Jitter time was:%fms.\nJitterTest exiting.\n", + (float)LastMaxDiff/1000.0); + + sprintf(tmpBuf, + "\nCtrl+C detected. Worst Jitter time was:%fms\nJitterTest exiting.\n", + (float)LastMaxDiff/1000.0); + Write(Fd1, tmpBuf, strlen(tmpBuf), __LINE__); + + Write(Cfd, tmpBuf, strlen(tmpBuf), __LINE__); + + close(Fd1); + close(Cfd); + exit(0); +} + + + + + +/* + A snapshot of the /proc/profile needs to be taken. + This is stored as a new file every time, and the + stats reset by doing a (any) write to the /proc/profile + file. + */ +void doGrabKProfile(int jitterusec, char *fileName) +{ + int fdSnapshot; + int fdProfile; + int readBytes; + char readBuf[4096]; + + if((fdSnapshot = open(fileName, O_WRONLY | O_CREAT)) <= 0) + { + fprintf(stderr, "Could not open file %s.\n", fileName); + perror("Error:"); + return; + } + + if((fdProfile = open("/proc/profile", O_RDWR)) <= 0) + { + fprintf(stderr, "Could not open file /proc/profile. Make sure you booted with profile=2\n"); + close(fdSnapshot); + return; + } + + while((readBytes = read(fdProfile, readBuf, sizeof(readBuf))) > 0) + { + write(fdSnapshot, readBuf, readBytes); + } + + close(fdSnapshot); + + if(write(fdProfile, readBuf, 1) != 1) + { + perror("Could Not clear profile by writing to /proc/profile:"); + } + + close(fdProfile); + + + +}/* end doGrabKProfile()*/ + + +/* + Call this routine to clear the kernel profiling buffer /proc/profile +*/ +void clearProfileBuf(void){ + + + int fdProfile; + char readBuf[10]; + + + if((fdProfile = open("/proc/profile", O_RDWR)) <= 0) + { + fprintf(stderr, "Could not open file /proc/profile. Make sure you booted with profile=2\n"); + return; + } + + + if(write(fdProfile, readBuf, 1) != 1) + { + perror("Could Not clear profile by writing to /proc/profile:"); + } + + close(fdProfile); + + +}/* end clearProfileBuf() */ + + + + + +/*********************************************************************** + * AlarmHandler + * This is a handler for the SIGALRM signal (due to the periodic + * timer interrupt). It prints the time (seconds) to + * the output file. + * output: N/A + ***********************************************************************/ +void AlarmHandler( + int sigNum) /* signal number (not used) */ +{ + + long timeDiffusec; /* diff time in micro seconds */ + long intervalusec; + + + char tmpBuf[MAX_WRITE_BYTES]; + int cntr; + char padChar; + + static int profileFileNo = 0; + char profileFileName[150]; + + static int seedStarter = 0; /* carries over rand info to next time + where time() will be the same as this time + if invoked < 1sec apart. + */ + + if (gettimeofday(&CurrTimeVal, NULL) == (int) 0) { + + /*---------------------------------------------------------------- + * Compute the elapsed time between the current and previous + * time of day values and store the result. + * + * Print the elapsed time to the output file. + *---------------------------------------------------------------*/ + + timeDiffusec = (long)(((((long long)CurrTimeVal.tv_sec) * 1000000L) + CurrTimeVal.tv_usec) - + (((long long)PrevTimeVal.tv_sec * 1000000L) + PrevTimeVal.tv_usec)); + + sprintf(tmpBuf," %f ms ", (float)timeDiffusec/1000.0); + + intervalusec = InterruptPeriodMilliSec * 1000L; + + timeDiffusec = timeDiffusec - intervalusec; + + sprintf(&tmpBuf[strlen(tmpBuf)]," %f ms", (float)timeDiffusec/1000.0); + + + /* should we send a SIGSTOP/SIGCONT to the specified PID? */ + if(SignalGCTask){ + + if(kill(GCTaskPID, SIGSTOP) < 0){ + + perror("error:"); + } + } + + + /* Store some historical #'s */ + if(abs(timeDiffusec) > LastMaxDiff) + { + LastMaxDiff = abs(timeDiffusec); + sprintf(&tmpBuf[strlen(tmpBuf)],"!"); + + if((GrabKProfile == TRUE) && (ProfileTriggerMSecs < (abs(timeDiffusec)/1000))) + { + sprintf(profileFileName, "JitterTest.profilesnap-%i", profileFileNo); + + /* go and grab the kernel performance profile. */ + doGrabKProfile(timeDiffusec, profileFileName); + profileFileNo++; /* unique name next time */ + + /* Say so on the console so that a marker gets put in the console log */ + sprintf(&tmpBuf[strlen(tmpBuf)],"<Profile saved in file:%s>", + profileFileName); + + } + + } + + + + + sprintf(&tmpBuf[strlen(tmpBuf)],"\n"); /* CR for the data going out of the console */ + + Write(Cfd, tmpBuf, strlen(tmpBuf), __LINE__); + + + /* The "-1" below takes out the '\n' at the end that we appended for the msg printed on + the console.*/ + sprintf(&tmpBuf[strlen(tmpBuf)-1]," PadBytes:"); + + /* Now pad the output file if requested by user. */ + if(WriteBytes > MIN_WRITE_BYTES) + { + + /* start from a new place every time */ + srand(time(NULL) + seedStarter); + + /* already written MIN_WRITE_BYTES by now */ + for(cntr = strlen(tmpBuf); cntr < WriteBytes - 1 ; cntr++) /* "-1" adj for '\n' at end */ + { + /* don't accept any # < 'SPACE' */ + padChar = (char)(MIN_ASCII+(int)((MAX_ASCII-(float)MIN_ASCII)*rand()/(RAND_MAX+1.0))); + + + /* + padChar = (cntr % (126-33)) + 33; + */ + + tmpBuf[cntr] = padChar; + } + + seedStarter = tmpBuf[cntr-1]; /* save for next time */ + + tmpBuf[cntr] = '\n'; /* CR for the data going into the outfile. */ + tmpBuf[cntr+1] = '\0'; /* NULL terminate the string */ + } + + /* write out the entire line to the output file. */ + Write(Fd1, tmpBuf, strlen(tmpBuf), __LINE__); + + + /* Read a byte from the specified file */ + if(DoRead) + { + + read(Fd2, tmpBuf, 1); + lseek(Fd2, 0, SEEK_SET); /* back to start */ + } + + + /* Start the periodic timer again. */ + setitimer(ITIMER_REAL, &ITimer, NULL); + + + /* Update previous time with current time. */ + PrevTimeVal.tv_sec = CurrTimeVal.tv_sec; + PrevTimeVal.tv_usec = CurrTimeVal.tv_usec; + } + + else { + sprintf(tmpBuf, "gettimeofday error \n"); + Write(Fd1, tmpBuf, strlen(tmpBuf), __LINE__); + + printf("gettimeofday error \n"); + } + + /* now clear the profiling buffer */ + if(GrabKProfile == TRUE){ + + clearProfileBuf(); + } + + /* should we send a SIGSTOP/SIGCONT to the specified PID? */ + if(SignalGCTask){ + + if(kill(GCTaskPID, SIGCONT) < 0){ + + perror("error:"); + } + } + + + return; +} + + + +/*********************************************************************** + * InitITimer + * This function initializes the 'struct itimerval' structure whose + * address is passed to interrupt every InterruptPeriodMilliSec. + * output: N/A + ***********************************************************************/ +void InitITimer( + struct itimerval * pITimer, /* pointer to interrupt timer struct*/ + int action) /* ONESHOT or autosetting? */ +{ + long seconds; /* seconds portion of int. period */ + long microSeconds; /* microsec. portion of int. period */ + + /*-------------------------------------------------------------------- + * Divide the desired interrupt period into its seconds and + * microseconds components. + *-------------------------------------------------------------------*/ + if (InterruptPeriodMilliSec < MILLISEC_PER_SEC) { + seconds = 0L; + microSeconds = InterruptPeriodMilliSec * MICROSEC_PER_MILLISEC; + } + else { + seconds = InterruptPeriodMilliSec / MILLISEC_PER_SEC; + microSeconds = + (InterruptPeriodMilliSec - (seconds * MILLISEC_PER_SEC)) * + MICROSEC_PER_MILLISEC; + } + + /* Initialize the interrupt period structure. */ + pITimer->it_value.tv_sec = seconds; + pITimer->it_value.tv_usec = microSeconds; + + if(action == ONESHOT) + { + /* This will (should) prevent the timer from restarting itself */ + pITimer->it_interval.tv_sec = 0; + pITimer->it_interval.tv_usec = 0; + }else + { + pITimer->it_interval.tv_sec = seconds; + pITimer->it_interval.tv_usec = microSeconds; + + } + + return; +} + + +/*********************************************************************** + * HandleCmdLineArgs + * This function handles the command line arguments. + * output: stack size + ***********************************************************************/ +void HandleCmdLineArgs( + int argc, /* number of command-line arguments */ + char *argv[]) /* ptrs to command-line arguments */ +{ + int argNum; /* argument number */ + + if (argc > (int) 1) { + + for (argNum = (int) 1; argNum < argc; argNum++) { + + /* The command line contains an argument. */ + + if ((strcmp(argv[argNum],"--version") == STRINGS_EQUAL) || + (strcmp(argv[argNum],"-v") == STRINGS_EQUAL)) { + /* Print version information and exit. */ + PrintVersionInfo(); + exit(0); + } + + else if ((strcmp(argv[argNum],"--help") == STRINGS_EQUAL) || + (strcmp(argv[argNum],"-h") == STRINGS_EQUAL) || + (strcmp(argv[argNum],"-?") == STRINGS_EQUAL)) { + /* Print help information and exit. */ + PrintHelpInfo(); + exit(0); + } + + else if ((strcmp(argv[argNum],"--file") == STRINGS_EQUAL) || + (strcmp(argv[argNum],"-f") == STRINGS_EQUAL)) { + /* Set the name of the output file. */ + ++argNum; + if (argNum < argc) { + SetFileName(argv[argNum]); + } + else { + printf("*** Output file name not specified. ***\n"); + printf("Default output file name will be used.\n"); + } + } + + else if ((strcmp(argv[argNum],"--time") == STRINGS_EQUAL) || + (strcmp(argv[argNum],"-t") == STRINGS_EQUAL)) { + /* Set the interrupt period. */ + ++argNum; + if (argNum < argc) { + SetInterruptPeriod(argv[argNum]); + } + else { + printf("*** Interrupt period not specified. ***\n"); + printf("Default interrupt period will be used.\n"); + } + + } + + else if ((strcmp(argv[argNum],"--priority") == + STRINGS_EQUAL) || + (strcmp(argv[argNum],"-p") == STRINGS_EQUAL)) { + /* Set the scheduler priority. */ + ++argNum; + if (argNum < argc) { + SetSchedulerPriority(argv[argNum]); + } + else { + printf("*** Scheduler priority not specified. ***\n"); + printf("Default scheduler priority will be used.\n"); + } + + } + + else if ((strcmp(argv[argNum],"--readfile") == + STRINGS_EQUAL) || + (strcmp(argv[argNum],"-r") == STRINGS_EQUAL)) { + /* Set the file to read*/ + ++argNum; + + strncpy(ReadFile, argv[argNum], sizeof(ReadFile)); + DoRead = TRUE; + } + + else if ((strcmp(argv[argNum],"--write_bytes") == + STRINGS_EQUAL) || + (strcmp(argv[argNum],"-w") == STRINGS_EQUAL)) { + /* Set the file to read*/ + ++argNum; + + WriteBytes = atoi(argv[argNum]); + + if(WriteBytes < MIN_WRITE_BYTES) + { + printf("Writing less than %i bytes is not allowed. Bye.\n", + MIN_WRITE_BYTES); + exit(0); + } + + + } + + else if ((strcmp(argv[argNum],"--consolefile") == + STRINGS_EQUAL) || + (strcmp(argv[argNum],"-c") == STRINGS_EQUAL)) { + /* Set the file to log console log on. */ + ++argNum; + + strncpy(LogFile, argv[argNum], sizeof(LogFile)); + } + + else if ((strcmp(argv[argNum],"--grab_kprofile") == + STRINGS_EQUAL)) + { + /* We will read the /proc/profile file on configurable timeout */ + GrabKProfile = TRUE; + + ++argNum; + + /* If the jittter is > this #, then the profile is grabbed. */ + ProfileTriggerMSecs = (long) atoi(argv[argNum]); + + if(ProfileTriggerMSecs <= 0){ + + printf("Illegal value for profile trigger threshold.\n"); + exit(0); + } + } + + else if ((strcmp(argv[argNum],"--siggc") == + STRINGS_EQUAL)) + { + /* We will SIGSTOP/SIGCONT the specified pid */ + SignalGCTask = TRUE; + + ++argNum; + + GCTaskPID = atoi(argv[argNum]); + + if(ProfileTriggerMSecs <= 0){ + + printf("Illegal value for JFFS(2) GC task pid.\n"); + exit(0); + } + } + + + else { + /* Unknown argument. Print help information and exit. */ + printf("Invalid option %s\n", argv[argNum]); + printf("Try 'JitterTest --help' for more information.\n"); + exit(0); + } + } + } + + return; +} + + +/*********************************************************************** + * SetFileName + * This function sets the output file name. + * output: N/A + ***********************************************************************/ +void SetFileName( + char * pFileName) /* ptr to desired output file name */ +{ + size_t fileNameLen; /* file name length (bytes) */ + + /* Check file name length. */ + fileNameLen = strlen(pFileName); + if (fileNameLen > (size_t) MAX_FILE_NAME_LEN) { + printf("File name %s exceeds maximum length %d.\n", + pFileName, MAX_FILE_NAME_LEN); + exit(0); + } + + /* File name length is OK so save the file name. */ + strcpy(OutFileName, pFileName); + + return; +} + + +/*********************************************************************** + * SetInterruptPeriod + * This function sets the interrupt period. + * output: N/A + ***********************************************************************/ +void SetInterruptPeriod( + char * /* ptr to desired interrupt period */ + pASCIIInterruptPeriodMilliSec) +{ + long period; /* interrupt period */ + + period = atol(pASCIIInterruptPeriodMilliSec); + if ((period < MIN_INT_PERIOD_MILLISEC) || + (period > MAX_INT_PERIOD_MILLISEC)) { + printf("Invalid interrupt period: %ld ms.\n", period); + exit(EXIT_INV_INT_PERIOD); + } + else { + InterruptPeriodMilliSec = period; + } + return; +} + + +/*********************************************************************** + * SetSchedulerPriority + * This function sets the desired scheduler priority. + * output: N/A + ***********************************************************************/ +void SetSchedulerPriority( + char * pASCIISchedulerPriority) /* ptr to desired scheduler priority*/ +{ + int priority; /* desired scheduler priority value */ + + priority = atoi(pASCIISchedulerPriority); + if ((priority < MinPriority) || + (priority > MaxPriority)) { + printf("Scheduler priority %d outside of range [%d, %d]\n", + priority, MinPriority, MaxPriority); + exit(EXIT_INV_SCHED_PRIORITY); + } + else { + RequestedPriority = priority; + RunAsRTTask = TRUE; /* We shall run as a POSIX real time task */ + } + return; +} + + +/*********************************************************************** + * PrintVersionInfo + * This function prints version information. + * output: N/A + ***********************************************************************/ +void PrintVersionInfo(void) +{ + printf("JitterTest version %s\n", Version); + printf("Copyright (c) 2001, Daniel Industries, Inc.\n"); + return; +} + + +/*********************************************************************** + * PrintHelpInfo + * This function prints help information. + * output: N/A + ***********************************************************************/ +void PrintHelpInfo(void) +{ + printf("Usage: JitterTest [options]\n"); + printf(" *** Requires root privileges. ***\n"); + printf("Option:\n"); + printf(" [-h, --help, -?] Print this message and exit.\n"); + printf(" [-v, --version] "); + printf( "Print the version number of JitterTest and exit.\n"); + printf(" [-f FILE, --file FILE] Set output file name to FILE. Typically you would put this on the fs under test\n"); + printf(" [-c FILE, --consolefile] Set device or file to write the console log to.\n\tTypically you would set this to /dev/console and save it on another computer.\n"); + printf(" [-w BYTES, --write_bytes BYTES Write BYTES to FILE each period.\n"); + printf(" [-r FILE, --readfile FILE] Also read 1 byte every cycle from FILE. FILE will be created and filled with data.\n"); + printf(" [-t <n>, --time <n>] "); + printf( "Set interrupt period to <n> milliseconds.\n"); + printf(" "); + printf( "Range: [%ld, %ld] milliseconds.\n", + MIN_INT_PERIOD_MILLISEC, MAX_INT_PERIOD_MILLISEC); + printf(" [-p <n>, --priority <n>] "); + printf( "Set scheduler priority to <n>.\n"); + printf(" "); + printf( "Range: [%d, %d] (higher number = higher priority)\n", + MinPriority, MaxPriority); + printf(" [--grab_kprofile <THRESHOLD in ms>] Read the /proc/profile if jitter is > THRESHOLD and store in file.\n"); + printf(" [--siggc <PID>] Before writing to fs send SIGSTOP to PID. After write send SIGCONT\n"); + return; + +} + + +/* A common write that checks for write errors and exits. Pass it __LINE__ for lineNo */ +int Write(int fd, void *buf, size_t bytes, int lineNo) +{ + + int err; + + err = write(fd, buf, bytes); + + if(err < bytes) + { + + printf("Write Error at line %i! Wanted to write %i bytes, but wrote only %i bytes.\n", + lineNo, bytes, err); + perror("Write did not complete. Error. Bye:"); /* show error from errno. */ + exit(1); + + } + + return err; + +}/* end Write*/ diff --git a/jittertest/Makefile b/jittertest/Makefile new file mode 100644 index 0000000..2f11329 --- /dev/null +++ b/jittertest/Makefile @@ -0,0 +1,46 @@ +CC=gcc +# uncomment following for performance +CCFLAGS=-O3 -Wall -m486 -fomit-frame-pointer + +# uncomment following for debugging. Uncomment either this or the one above. Not both. +# CCFLAGS=-Wall -g + + +all: JitterTest plotJittervsFill + +JitterTest: JitterTest.c Makefile + gcc $(CCFLAGS) -lm JitterTest.c -o JitterTest + +plotJittervsFill: plotJittervsFill.c Makefile + gcc $(CCFLAGS) plotJittervsFill.c -o plotJittervsFill + +clean: + rm -rf *~ + rm -rf core + rm -rf *.o + rm -rf JitterTest + + +dep: + makedepend -I./ *.c +# DO NOT DELETE + +JitterTest.o: /usr/include/stdio.h /usr/include/features.h +JitterTest.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h +JitterTest.o: /usr/lib/gcc-lib/i386-redhat-linux/egcs-2.91.66/include/stddef.h +JitterTest.o: /usr/lib/gcc-lib/i386-redhat-linux/egcs-2.91.66/include/stdarg.h +JitterTest.o: /usr/include/bits/types.h /usr/include/libio.h +JitterTest.o: /usr/include/_G_config.h /usr/include/bits/stdio_lim.h +JitterTest.o: /usr/include/string.h /usr/include/stdlib.h +JitterTest.o: /usr/include/sys/types.h /usr/include/time.h +JitterTest.o: /usr/include/endian.h /usr/include/bits/endian.h +JitterTest.o: /usr/include/sys/select.h /usr/include/bits/select.h +JitterTest.o: /usr/include/bits/sigset.h /usr/include/sys/sysmacros.h +JitterTest.o: /usr/include/alloca.h /usr/include/sys/time.h +JitterTest.o: /usr/include/bits/time.h /usr/include/signal.h +JitterTest.o: /usr/include/bits/signum.h /usr/include/bits/siginfo.h +JitterTest.o: /usr/include/bits/sigaction.h /usr/include/bits/sigcontext.h +JitterTest.o: /usr/include/asm/sigcontext.h /usr/include/bits/sigstack.h +JitterTest.o: /usr/include/sched.h /usr/include/bits/sched.h +JitterTest.o: /usr/include/unistd.h /usr/include/bits/posix_opt.h +JitterTest.o: /usr/include/bits/confname.h /usr/include/getopt.h diff --git a/jittertest/README b/jittertest/README new file mode 100644 index 0000000..f411a2c --- /dev/null +++ b/jittertest/README @@ -0,0 +1,197 @@ +$Id: README,v 1.2 2001/08/10 19:23:11 vipin Exp $ + +This is the README file for the JitterTest (and friends) +program. + +This program is used to measure what the jitter of a +real time task would be under "standard" Linux. + +More particularly, what is the effect of running +a real time task under Linux with background +JFFS file system activity. + +The jitter is measured in milli seconds (ms) from +the expected time of arrival of a signal from a +periodic timer (set by the task) to when the +task actually gets the signal. + +This jitter is then stored in a file specified +(or the default output file "jitter.dat"). + +The data may also be sent out to the console by +writing to /dev/console (See help options. This is +highly desirable specially if you have redirected +your console to the serial port and are storing it +as a minicom log on another computer for later analysis +using some tools provided here). + +This is particularly useful if you have a serial +console and are outputting "interesting" info +from inside some kernel task or driver. +(or something as simple as a "df" program running +periodically and redirecting o/p to the console). + +One "interesting" thing that I have measured +is the effect of FLASH chip erases on the jitter +of a real time task. + +One can do that by putting a printk at the +beginning of the flash erase routine in the MTD +flash chip driver. + +Now you will get jitter data interspersed with +flash sector erase events. Other printk's can also +be placed at suspected jitter causing locations in +the system. + + + +EXECUTING THE PROGRAM "JitterTest" + +You may specify a file to be read by the +program every time it wakes up (every cycle). +This file is created and filled with some junk +data. The purpose of this is to test the jitter +of the program if it were reading from- say +a JFFS (Journaling Flash File System) file system. + +By specifying the complete paths of the read and write +(o/p) files you can test the jitter a POSIX type +real time task will experience under Linux, under +various conditions. + +These can be as follows: + +1. O/P file on ram file system, no i/p file. + + In this case you would presumably generate other +"typical" background activity for your system and +examine the worst case jitter experienced by +a task that is neither reading nor writing to +a file system. + +Other cases could be: + +2. O/P to ram fs, I/P from JFFS (type) fs: + + This is specially useful to test the proper +operation of erase suspend type of operation +in JFFS file systems (with an MTD layer that +supports it). + + In this test you would generate some background +write/erase type activity that would generate +chip erases. Since this program is reading from +the same file system, you contrast the latencies +with those obtained with writes going to the same +fs. + +3. Both read and writes to (or just write to) JFFS +file system: + + Here you would test for latencies experienced by +a program if it were writing (and optionally also +reading) from a JFFS fs. + + + + +Grabing a kernel profile: + +This program can also conditionally grab a kernel profile. +Specify --grab_kprofile on the cmd line as well as +a "threshold" parameter (see help options by -?). + +Any jitter greater than this "threshold" will cause the +program to read the /proc/profile file and dump it in +a local file with increasing file numbers. It will also +output the filename at that time to the console file specified. +This will allow you to corelate later in time the various profiles +with data in your console file and what was going on at that time. + +These profile files may then be later examined by running them through +ksymoops. + +Make sure you specify "profile=2" on the kernel command line +when you boot the kernel if you want to use this functionality. + + + +Signalling the JFFS[2] GC task: + +You can also force this program to send a SIGSTOP/SIGCONT to the +JFFS (or JFFS2) gc task by specifing --siggc <pid> on the cmd line. + +This will let you investigate the effect of forcing the gc task to +wake up and do its thing when you are not writing to the fs and to +force it to sleep when you want to write to the fs. + +These are just various tools to investigate the possibility of +achieving minimal read/write latency when using JFFS[2]. + +You need to manually do a "ps aux" and look up the PID of the gc +thread and provide it to the program. + + + + +EXECUTING THE PROGRAM "plotJittervsFill" + +This program is a post processing tool that will extract the jitter +times as printed by the JitterTest program in its console log file +as well as the data printed by the "df" command. + +This "df" data happens to be in the console log because you will +run the shell file fillJffs2.sh on a console when you are doing +your jitter test. + +This shell script copies a specified file to another specified file +every programmable seconds. It also does a "df" and redirects output +to /dev/console where it is mixed with the output from JitterTest. + +All this console data is stored on another computer, as all this data +is being outputted to the serial port as you have redirected the console +to the serial port (that is the only guaranteed way to not loose any +console log or printk data). + +You can then run this saved console log through this program and it +will output a very nice text file with the %fill in one col and +corrosponding jitter values in the second. gnuplot then does a +beautifull plot of this resulting file showing you graphically the +jitters encountered at different fill % of your JFFS[2] fs. + + + +OTHER COMMENTS: + +Use the "-w BYTES" cmd line parameter to simulate your test case. +Not everyone has the same requirements. Someone may want to measure +the jitter of JFFS2 with 500 bytes being written every 500ms. Others +may want to measure the system performance writing 2048 bytes every +5 seconds. + +RUNNING MULTIPLE INSTANCES: + +Things get real interesting when you run multiple instances of this +program *at the same time*. + +You could have one version running as a real time task (by specifing +the priority with the -p cmd line parameter), not interacting with +any fs or at the very least not reading and writing to JFFS[2]. + +At the same time you could have another version running as a regular +task (by not specifing any priority) but reading and writing to JFFS[2]. + +This way you can easily measure the blocking performance of the real time +task while another non-real time task interacts with JFFS[2] in the back ground. + +You get the idea. + + +WATCH OUT! + +Be particularly careful of running this program as a real time task AND +writing to JFFS[2]. Any blocks will cause your whole system to block till +any garbage collect initiated by writes by this task complete. I have measured +these blocks to be of the order of 40-50 seconds on a reasonably powerful +32 bit embedded system. diff --git a/jittertest/filljffs2.sh b/jittertest/filljffs2.sh new file mode 100644 index 0000000..10651f4 --- /dev/null +++ b/jittertest/filljffs2.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +# Pass following cmd line: +# 1st - file to copy +# 2nd - file to copy to +# 3rd - time to sleep between copies + +while [ $(( 1 )) -gt $(( 0 )) ] +do + cp $1 $2 + rm $2 + df |grep mtd > /dev/console + echo "sleeping $3" + sleep $3 +done + diff --git a/jittertest/plotJittervsFill.c b/jittertest/plotJittervsFill.c new file mode 100644 index 0000000..f8a5660 --- /dev/null +++ b/jittertest/plotJittervsFill.c @@ -0,0 +1,312 @@ +/* + *********************************************************************** + * + * Copyright: Daniel Measurement and Control, Inc. + * 9753 Pine Lake Drive + * Houston, TX 77055 + * + * Created by: Vipin Malik + * Released under GPL by permission of Daniel Industries. + * + * This software is licensed under the GPL version 2. Plese see the file + * COPYING for details on the license. + * + * NO WARRANTY: Absolutely no claims of warranty or fitness of purpose + * are made in this software. Please use at your own risk. + * + File: plotJittervsFill.c + By: Vipin Malik + + About: This program reads in a jitter log file as created + by the JitterTest.c program and extracts all the jitters + in the file that are greater than a threshold specified + as a parameter on the cmd line. It also extracts the + amount of disk space at (form the "df" out that should also + be present in the log file) after the jitter extracted. + + It writes the data to the stderr (where you may redirect it). + It is suitable for plotting, as the data is written as + COL1=UsedSpace COL2=Jitter + + $Id: plotJittervsFill.c,v 1.6 2005/11/07 11:15:21 gleixner Exp $ + $Log: plotJittervsFill.c,v $ + Revision 1.6 2005/11/07 11:15:21 gleixner + [MTD / JFFS2] Clean up trailing white spaces + + Revision 1.5 2001/08/10 19:23:11 vipin + Ready to be released under GPL! Added proper headers etc. + + Revision 1.4 2001/07/02 22:25:40 vipin + Fixed couple of minor cosmetic typos. + + Revision 1.3 2001/07/02 14:46:46 vipin + Added a debug option where it o/p's line numbers to debug funky values. + + Revision 1.2 2001/06/26 19:48:57 vipin + Now prints out jitter values found at end of log file, after which + no new "df" disk usage values were encountered. The last "df" disk usage + encountered is printed for these orphaned values. + + Revision 1.1 2001/06/25 19:13:55 vipin + Added new file- plotJittervsFill.c- that mines the data log file + outputed from the fillFlash.sh script file and JitterTest.c file + and produces output suitable to be plotted. + This output plot may be examined to see visually the relationship + of the Jitter vs disk usage of the fs under test. + + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> + +static char Version_string[] = "$Id: plotJittervsFill.c,v 1.6 2005/11/07 11:15:21 gleixner Exp $"; +static char LogFile[250] = "InputLogFile.log"; + +static int JitterThreshold_ms = 1000; +static int Debug = 0; /* Debug level. Each "-d" on the cmd line increases the level */ + +#define TRUE 1 +#define FALSE 0 + +#define MIN_JITTER_THRESHOLD 1 /* ms minimum jitter threshold */ + +void PrintHelpInfo(void) +{ + printf("Usage: plotJittervsFill [options] -f [--file] <input log file name> -t [--jitter_threshold] <jitter threshold in ms>\n"); + printf("[options]:\n-v [--version] Print version and exit\n"); + printf("-d Debug. Prints input file line number for each data point picked up.\n"); + printf("-h [--help] [-?] Print this help screen and exit.\n"); +} + + + +/*********************************************************************** + * HandleCmdLineArgs + * This function handles the command line arguments. + * output: stack size + ***********************************************************************/ +void HandleCmdLineArgs( + int argc, /* number of command-line arguments */ + char *argv[]) /* ptrs to command-line arguments */ +{ + int argNum; /* argument number */ + + if (argc > (int) 1) { + + for (argNum = (int) 1; argNum < argc; argNum++) { + + /* The command line contains an argument. */ + + if ((strcmp(argv[argNum],"--version") == 0) || + (strcmp(argv[argNum],"-v") == 0)) { + /* Print version information and exit. */ + printf("%s\n", Version_string); + exit(0); + } + + else if ((strcmp(argv[argNum],"--help") == 0) || + (strcmp(argv[argNum],"-h") == 0) || + (strcmp(argv[argNum],"-?") == 0)) { + /* Print help information and exit. */ + PrintHelpInfo(); + exit(0); + } + + else if ((strcmp(argv[argNum],"--file") == 0) || + (strcmp(argv[argNum],"-f") == 0)) { + /* Set the name of the output file. */ + ++argNum; + if (argNum < argc) { + strncpy(LogFile, argv[argNum], sizeof(LogFile)); + } + else { + printf("*** Input file name not specified. ***\n"); + exit(0); + } + } + + else if ((strcmp(argv[argNum],"--jitter_threshold") == 0) || + (strcmp(argv[argNum],"-t") == 0)) { + /* Set the file to read*/ + ++argNum; + + JitterThreshold_ms = atoi(argv[argNum]); + + if(JitterThreshold_ms < MIN_JITTER_THRESHOLD) + { + printf("A jitter threshold less than %i ms is not allowed. Bye.\n", + MIN_JITTER_THRESHOLD); + exit(0); + } + } + + else if ((strcmp(argv[argNum],"-d") == 0)) + { + /* Increment debug level */ + + Debug++; + } + + else { + /* Unknown argument. Print help information and exit. */ + printf("Invalid option %s\n", argv[argNum]); + printf("Try 'plotJittervsFill --help' for more information.\n"); + exit(0); + } + } + } + + return; +} + + + + + +int main( + int argc, + char *argv[]) +{ + + char lineBuf[1024]; /* how long a single line be? */ + int converted; + int lineNo = 0; + int cnt; + + FILE *fp; + + int junkInt1, junkInt2, junkInt3; + float junkFloat1; + float jitter_ms; + +#define MAX_SAVE_BUFFER 1000 /* How many values will be picked up while searching for + a % disk full line (i.e. before they can be printed out) + */ + int saveJitter[MAX_SAVE_BUFFER]; /* lets us record multiple jitter values that exceed + our threshold till we find a "df" field- which is when + we can o/p all these values. + */ + int dataLineNo[MAX_SAVE_BUFFER]; /* The saved line #'s for the above. Printed if debug specified. */ + + int saveJitterCnt = 0; + int lookFor_df = FALSE; + int dfPercent = -1; /* will be >= 0 if at least one found. The init value is a flag. */ + + char junkStr1[500], junkStr2[500]; + + HandleCmdLineArgs(argc, argv); + + if((fp = fopen(LogFile, "r")) == NULL) + { + printf("Unable to open input log file %s for read.\b", LogFile); + perror("Error:"); + exit(1); + } + + + + while(fgets(lineBuf, sizeof(lineBuf), fp) != NULL) + { + lineNo++; + + + /* Are we looking for a "df" o/p line? (to see how full + the flash is?)*/ + + /* is there a "%" in this line? */ + if((strstr(lineBuf, "%") != NULL) && (lookFor_df)) + { + converted = sscanf(lineBuf, "%s %i %i %i %i\n", + junkStr1, &junkInt1, &junkInt2, &junkInt3, &dfPercent); + if(converted < 5) + { + printf("Line %i contains \"%%\", but expected fileds not found. Skipping.\n", lineNo); + }else + { + /* Now print out the saved jitter values (in col2) with this dfPercent value as the col1. */ + for(cnt = 0; cnt < saveJitterCnt; cnt++) + { + if(Debug) + { + fprintf(stderr, "%i\t%i\t%i\n", (int)dataLineNo[cnt], + dfPercent, (int)saveJitter[cnt]); + }else + { + fprintf(stderr, "%i\t%i\n", dfPercent, (int)saveJitter[cnt]); + } + + + } + + saveJitterCnt = 0; /* all flushed. Reset for next saves. */ + lookFor_df = FALSE; + } + + } + + + /* is there a "ms" in this line?*/ + if(strstr(lineBuf, "ms") == NULL) + { + continue; + } + + /* grab the ms jitter value */ + converted = sscanf(lineBuf, "%f %s %f %s\n", &junkFloat1, junkStr1, &jitter_ms, junkStr2); + if(converted < 4) + { + printf("Line %i contains \"ms\", but expected fileds not found. Converted %i, Skipping.", + lineNo, converted); + printf("1=%i, 2=%s.\n", junkInt1, junkStr1); + continue; /* not our jitter line*/ + } + + /* Is the jitter value > threshold value? */ + if(abs(jitter_ms) > JitterThreshold_ms) + { + /* Found a jitter line that matches our crietrion. + Now set flag to be on the look out for the next + "df" output so that we can see how full the flash is. + */ + + if(saveJitterCnt < MAX_SAVE_BUFFER) + { + saveJitter[saveJitterCnt] = (int)abs(jitter_ms); /* why keep the (ms) jitter in float */ + dataLineNo[saveJitterCnt] = lineNo; + saveJitterCnt++; + lookFor_df = TRUE; + } + else + { + printf("Oops! I've run out of buffer space before I found a %% use line. Dropping itter value. Increase MAX_SAVE_BUFFER and recompile.\n"); + } + + + } + + } + + + /* Now print out any saved jitter values that were not printed out because we did not find + and "df" after these were picked up. Only print if a "df" disk usage was ever found. + */ + if(lookFor_df && (dfPercent >= 0)) + { + /* Now print out the saved jitter values (in col2) with this dfPercent value as the col1. */ + for(cnt = 0; cnt < saveJitterCnt; cnt++) + { + fprintf(stderr, "%i\t%i\n", dfPercent, (int)saveJitter[cnt]); + } + } + + return 0; + + +}/* end main() */ + + + + |