[Reserved LinuxAID] How to read the source code

xiaoxiao2021-03-06  18

http://www.linuxaid.com.cn/Articles/8/6/861776524.shtml

Thank you for such a wonderful article on LinuxAid!!!

Analysis of a source code, an effective method is: 1. Read the source code documentation, such as the readme in this example, the author writes very detailed, after reading it, often from the readme file when reading the program Find the appropriate description to simplify the reading of the source program. 2. If the source code has a document directory, it is generally DOC or DOCS, it is best to read carefully before reading the source program, because these documents have a good explanation of annotations. 3, start from the Makefile file, analyze the hierarchy of the source code, find which is the main program, which is a function package. This is a great help to quickly grasp the program structure. 4, start from the main function, read down one step, encounter simple functions that can be speculated, you can skip. But must pay attention to the global variable used in the program (if a C program), you can copy the critical data structure instructions to a text editor to find it at any time. 5. Analyze function packs (for C procedures), pay attention to which is a full function, which is the internal functions, pay attention to the extern keyword. Also pay attention to variables. First analyze the internal functions, then analyze the external function, because the internal function is definitely called in an external function. 6, the importance of the data structure is required: For a C program, all functions are operated with some data, and these data may appear anywhere in the program because there is no better encapsulation. Any function modification, so be noted to pay attention to the definition and meaning of these data, but also to note which functions are operated on them, what changes do it. 7. While reading the program, it is best to deploy the program into the version of the controller and the source code. You can do some modified tests on the source code when needed, because the hands modification is better than just reading. The method of reading the program. When you modify the running program, you can call the original code from the CVS to compare the part of your change (DIFF command), you can see some source code advantages and disadvantages and can practice your programming technology. 8. While reading the program, pay attention to the use of some gadgets, can improve the speed, such as the lookup feature in the VI, mode matching, make a tag, and grep, find these two most powerful text search tools usage of.

How to read the source code - Tools

Original 02-01-21 09:10 15860P Ariesram

In the previous article (<< How to read the source code >> (http://www.linuxaid.com.cn/developer/showdev.jsp?i=469)), I tell some of the GNU, Open Source Source code principles, experience and techniques. Last time I mentioned that some tools can help us more quickly, accurately, and effectively read the source code, and master their structure. In this article, I will introduce several tools to help us read and analyze source code. The tool to be introduced is called CTags. This tool is a commonly used tool for analyzing the static program under UNIX. I believe everyone has used. If you are not familiar with this tool, don't matter. I believe that many people have used development tools under the Windows system, many graphical interface development tools, such as Visual C , C Builder's IDE development environment provides a function, which is to locate a function accurately in the editor or A class of statements, or implementations, or list all places where the function is called in the program. This feature provides a lot of convenience to the programmer and the reader. Don't search for a string everywhere in a huge program text. As long as you look at the mouse, you can find something you want to find. In fact, UNIX / Linux also has such a tool, inherits the Unix program compact, refining, powerful, easy to cooperate with other programs, more convenient than Visual C , C Builder's IDE environment, but also without them huge. CTAGS combines VI, which is such a tool. Let's take a look at the function of CTAGS under UNIX. I use HP UX. There is such a small program, which is used to explain the use of CTAGS. $ cat test.cint i; main () {f (); g (); f ();} f () {i = h ();} A tags file is generated with commands. $ ctags test.c By default, the file generated by the CTAGS is called Tags. Let's take a look at it. $ Cat tagsmtest Test.c / ^ Main () $ / f Test.c / ^ f () $ / This file has three columns: 1, the name of the tag, you can locate the cursor later by reference. 2, the name of the file. This file is the name of the file where TAG is located. 3, search method. On my system, CTAGS is searched in a regular expression. How to use this tags file? We use VI as an example to show its function. VI is a powerful text editor, its simple operation and powerful function makes it the most popular editor on the UNIX platform. CTAGS supports VI functionality. The method is very simple. If we want to locate the main () function, as long as the Test.c file is opened automatically, then position the cursor to the beginning of the main () function. In VI, if you want to use other tags to locate other functions, just use: ta tag commands. For example, in this case, we have to locate the F function. So, as long as the TA F cursor is automatically positioned to the entrance to the F () function. Very simple? Under Linux, you can also find CTAGS. The general Linux distribution includes this tool. If there is no CTAGS on your system, you can also download it at http://ctags.sourceforge.net/.

Its author is Darren Hiebert , , home address is http://darren.hiebert.com/linux CTAGS is more powerful than the CTAGS function under Unix, And more customizable. CTAGS under UNIX (I do this is like this) only three languages: C, Pascal, Fortran, and CTAGS support under Linux: Assembler, AWK, Beta, Bourne Shell, C / C , COBOL, Eiffel , Fortran, Java, Lisp, Perl, Python, Scheme, Tcl. And there are also many editors supported under Linux, with: VI and its derived Vim, Vile, Lemmy, Crisp, Emacs, FTE (FTE (FTE (Forting Text Editor) Nedit (Nirvana Edit), Tse (The Semware Editor), X2, Zeus. Well, let us take a look at the powerful features of CTAGS and it is when you read the source code. I will still be an example of Webalizer, because this program is used in the previous article << How to read the source code >>, in order to consisten, and readers can learn more about this program and learn more about this article To more experience skills. Consider it, when we get a C program, how can we quickly grasp its structure? The C program consists of a series of functions, variables, macros, and pre-compiled instructions. And our most concerned is the function, and global variables. Well, you can easily get what we are interested in using CTags.

As an example of Webalizer's main program Webalizer.c as an example, we can use: [Webalizer-2.01-09] $ ctags -x --c-types = f Webalizer.c The result is as follows Clear_Mont Function 1614 Webalizer.c void clear_month () ctry_idx function 1738 webalizer.c u_long ctry_idx (char * str) cur_time function 1695 webalizer.c char * cur_time () from_hex function 1751 webalizer.c char from_hex (char c) / * convert hex to dec * / get_config function 1358 webalizer.c void get_config (char * fname) get_domain function 1852 webalizer.c char * get_domain (char * str) init_counters function 1627 webalizer.c void init_counters () ispage function 1714 webalizer.c int ispage (char * str) isurlchar function 1728 webalizer.c int isurlchar (char ch) jdate function 1919 webalizer.c u_long jdate (int day, int month, int year) main function 231 webalizer.c int main (int argc, char * argv []) our_gzgets function 1873 webalizer.c char * Our_gzgets (Gzfile FP, Char * BUF, INT Size) Print_opts Function 1657 Webalizer.c Void Print_OPTS (Char * PNAME) Print_Version Function 1670 Webalizer.c Void Print_VER sion () save_opt function 1600 webalizer.c static char * save_opt (char * str) srch_string function 1794 webalizer.c void srch_string (char * ptr) unescape function 1763 webalizer.c char * unescape (char * str) can be seen in the output To all functions in Webalizer.c, the line number, and their declaration. Is convenient? (Of course, just this is not to read the source code, or need the principles and skills in the previous article to learn the source code. This is just an auxiliary tool, which can make us more convenient and accurate and accurate).

It is also very simple to see the prototype of the function: [Webalizer-2.01-09] $ ctags -x --c-types = p Webalizer.c The result is as follows Clear_Month Prototype 87 Webalizer.c void clear_month (); / * Clear Monthly Stuff * / from_hex prototype 89 webalizer.c char from_hex (char); / * convert hex to dec * / get_config prototype 93 webalizer.c void get_config (char *); / * Read a config file * / get_domain prototype 96 webalizer.c char * get_domain (char *); / * return domain name * / isurlchar prototype 92 webalizer.c int isurlchar (char);. / * valid URL char fnc * / our_gzgets prototype 97 webalizer.c char * our_gzgets (gzFile, char *, int); / * our gzgets * / print_opts prototype 90 webalizer.c void print_opts (char *); / * print options * / print_version prototype 91 webalizer.c void print_version (); / * duhh ... * / save_opt prototype 94 webalizer.c static char * save_opt (char *); / * save conf option * / srch_string prototype 95 webalizer.c void srch_string (char *); / * srch str analysis * / unescape prototype 88 webalizer.c char * unescape (char *); / * Unescape url's * / can also see the variables in the program : [Webalizer-2.01-09] $ ctags -x --c-types = v Webalizer.c | More get the result of all_agents variable 157 Webalizer.c Int All_agents = 0; / * list all user agents * / all_refs variable 156 webalizer.c int all_refs = 0; / * List All referrers * / all_search variable 158 webalizer.c int all_search = 0; / * List All Search Strings * / all_sites variable 154 webalizer.c int all_sites = 0; / * List All sites (0 = no) * / all_urls var all_urls = 0; / * list all url's (0 = no) * / all_users variable 159 Webalizer.c int all_users = 0; / * list all usrnames * / blank_str variable 138 Webalizer.c Char * Blank_str = ""; / * blank string * / buffer variable 217 Webalizer.c char buffer [buffsize];

/ * Log file record buffer * / check_dup variable 179 webalizer.c int check_dup = 0; / * check for dup flag * / conf_fname variable 135 webalizer.c char * conf_fname = NULL; / * name of config file * / copyright variable 106 webalizer.c char * copyright = "Copyright 1997-2001 by Bradford L. Barrett"; ctry_graph variable 117 webalizer.c int ctry_graph = 1; / * country graph display * / cur_day variable 171 webalizer.c cur_day = 0, cur_hour = 0 , / * tracking variables * / cur_hour variable 171 webalizer.c cur_day = 0, cur_hour = 0, / * tracking variables * / cur_min variable 172 webalizer.c cur_min = 0, cur_sec = 0; cur_month variable 170 webalizer.c int cur_year = 0, CUR_MONTH = 0, / * y Due to too much content, it is not one listed here. Readers can practice themselves. With the same command format, you can see more content, specified with -c-types. They are: C-class D macro definition E enumeration F function definition g Enumeration Name M, Structure and Union N namespace P function original and declared Structure Name T typedef u Joint Name V variable declares X external and reference variables You may not specify - C-Types to list all types.

You can also use this command format to analyze .h header files, for example, enumerate all macros defined in the Webalizer.h header file, [Webalizer-2.01-09] $ CTAGS -X --C-Types = D Webalizer. H | morebufsize macro 14 Webalizer.h #define buffs 4096 / * max buffer size for log record * / idx_2c macro 5 Webalizer.h #define IDX_2C (C1, C2) (((C1-'A ' 1) << 5 (C2-'A ' 1)) IDX_3C Macro 6 Webalizer.h #define IDX_3C (C1, C2, C3) (((C1-'A' 1) << 10) ((C2-'A) ' 1) << 5) (C3-'a' 1)) IDX_4C Macro 7 Webalizer.h #define IDX_4C (C1, C2, C3, C4) (((C1-'A ' 1) << 15) ((C2-'A ' 1) << 10) ((C3-'A' 1) << 5) (C4-'A ' 1)) IDX_ACCEPTED Macro 81 Webalizer.h # define IDX_ACCEPTED 5 IDX_BAD macro 93 webalizer.h #define IDX_BAD 17 IDX_BADGATEWAY macro 113 webalizer.h #define IDX_BADGATEWAY 37 IDX_BADHTTPVER macro 116 webalizer.h #define IDX_BADHTTPVER 40 IDX_CONFLICT macro 102 webalizer.h #define IDX_CONFLICT 26 IDX_CONTINUE macro 77 webalizer.h # define IDX_CONTINUE 1IDX_CREATED macro 80 webalizer.h #define IDX_CREATED 4 IDX_EXPECTATIONFAILED macro 110 webalizer.h #define IDX_EXPECTATIONFAILED 34 (because the length is too long, all failed listed below omitted) of course, is not the only function of the ctags So many, more important functions are generated a tags file, so that the function, class or other source code can be quickly locate functions in the VI editor. The default file name generated by CTags is Tags, or you can specify a file name with CTAGS -F. However, the default file name tags is also the default TAG file name of VI, which generally does not need to change. In this example, we use [Webalizer-2.01-09] $ ctags * .c to generate all the Tags of all .c files. Of course, if the source code is in many subdirectories, you can also pass all the * .c files in the current subdirectory through the parameters --Recurse. Take a look at the content of the tags file.

[Webalizer-2.01-09] $ head tags _TAG_FILE_FORMAT 2 / extended format;! --Format = 1 will not append;!! "To lines / _ TAG_FILE_SORTED 1/0 = unsorted, 1 = sorted / _ TAG_PROGRAM_AUTHOR Darren Hiebert / darren @ hiebert ! .com / _ TAG_PROGRAM_NAME Exuberant Ctags // _ TAG_PROGRAM_URL http://ctags.sourceforge.net / official site / _ TAG_PROGRAM_VERSION 4.0.3 // BLACK output.c 118;!! "d file: BLUE output.c 122;" d file : CLK_TCK DNS_RESOLV.C 71; "D file: CLK_TCK HASHTAB.C 59;" D file: You can see that the file is divided into columns, the first column is the name of the tag, such as the function put_unode, its Tag name is PUT_UNODE. The second column is the file name, which is the name of the file containing the TAG. The third column is the location of the function (or other) in the ex command. This ex command is different from the commands generated under Unix, but You can also specify the type of command through the command line. After generating the tags file, we can easily and accurately position the information we need to find in many and huge source code files. Or examples of VI, such as we want Positioning the main () function, as long as [Webalizer-2.01-09] $ VI -T Mainvi automatically opens the webalizer.c file, position the cursor to the start position of the 231st row, this is the port position of the main () function. In the VI editor, if you want to find the PUT_UNODE () function, as long as the TA PUT_UNODE, VI automatically opens the file HashTab.c, and the cursor is automatically positioned to the start position of the 344 row, this is the start position of PUT_UNODE. For example, we have to find a certain variable um_htab, as long as ta um_htab, we can quickly locate the 88th line of the Hashtab.c file. You can also pass any TAG by: ta tag this EX command to position any TAG. Need to pay attention Yes, there is this tags file, let's go to open one A specific source code file to find this TAG, VI will open this file automatically, which is very convenient. Of course, CTAGS is a very powerful tool. The reader can refer to its Man Page or access its website to discover more features. Another tool similar to the CTAGS is Etags, which is an editor Emacs (I believe many people like this editor, its functions are too complicated :-)) Dedicated tools, functional and CTAGS basically, different Yes, the default file generated by ETags is tags, which is defaults to the tag file by Emacs. There are also some tools, and CTAGs have similar functions. They are cxref (http://www.gedanken.def) CXREF to generate a document referenced to the C source code to generate LaTex, HTML, RTF, or SGML format. But it does not support C , and its authors do not seem to increase the ability to support C . cflow (http://www.opengroup.org/onlinepubs/7908799/xcu/cflow.html) is also a tool for generating documents and is a common tool under UNIX.

For example, on my HP UX platform, there is such a source code $> cat test.cint i; main () {f (); g (); f ();} f () {i = h Use cflow can be obtained: $> cflow test.c1 main: int (), 2 f: int (), 3 h: <> 4 g: <> column The file names and line numbers that appear in the function, as well as the call relationship (indicated by row indentation). Take some of the tools for some static analysis procedures. The following is a tool for some dynamic analysts. Dynamic analysis tools are also an important analysis tool. Because when a program is too big, it is very wasted by people to read this program, and the efficiency is not high. With dynamic analysis tools, you can quickly and accurately analyze a program, get some information, for example, where is your program spent a lot of time, what function calls, a function calls how many times, and so on. This information can help you know where your program is executed, you can help you rewrite these program code than what you think, you can help you override the program's running speed. These information can also tell you that those functions are more than or less than your expected number, helping you locate errors and correct bugs. Of course, this information is dynamically obtained when your program is running, so if some of your programs are not executed, then the dynamic analysis tool is not available to the part of the code. of. Below, let's take a look at a useful dynamic analysis tool: gprof. Like most Linux programs, this gprof also has its UNIX predecessor: PROF. On my HP UX system, PROF is provided. To use it, and the method using GPROF is basically the same, the result is similar. So let's go directly to the GPROF usage. Using GPROF includes three steps: 1, compiling your program, allowing it to use GPROF. 2, execute the program, generate an analysis result file. 3, run GPROF, analyze the results. Below, it is still a combination of our example, Webalizer to tell GPROF usage. First, we want to modify the webalizer's makefile. When you get the source code package of Webalizer, use Tar to see it, you will see a series of files in its unproved directory, where Makefile.in Makefile .std, but there is no Makefile file. You must use ./configure to configure the system to automatically generate a makefile file based on your system.

This is this after the Makefile file is completed (I lists the contents of the file, and I explain it in it, the Chinese characters are my explanation rather than the content of the Makefile file) [Webalizer-2.01-09] $ cat makefile # generated . automatically from Makefile.in by configure ## Makefile for webalizer - a web server log analysis program ## Copyright (C) 1997-2000 Bradford L. Barrett (brad@mrunix.net) ## 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, and provided that the above # copyright and permission notice is included with all distributed # copies of this or derived software ## 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 (file "copying"). # The above note describes the copyright information of this program, the author, the time, copyright, etc. PREFIX = / export / home / alan / webalizer Top this line defines the program's installation path EXEC_PREFIX = $ {prefix} This is the execution program installation path bindir = $ {exec_prefix} / bin This is the installation path of binary file Mandir = $ {prefix} / man / man1 This is MANPAGES installation path etcdir = / export / home / Alan / Webalizer / etc This is the installation path of the configuration file CC = GCC specifies the compiler is gccccflags = -wall -O2 compile option libs = - lgd -lpng -lz -lm library DEFS = -DETCDIR = "/ etc" connected -DHAVE_GETOPT_H = 1 -DHAVE_MATH_H = 1 LDFLAGS = compile option INSTALL = / usr / bin / install -cINSTALL_PROGRAM = $ {INSTALL} INSTALL_DATA = $ {Install} -m 644 installer # Where are the gd header files? GDLIB = / usr / include # Shouldn '

T Have to Touch Below here!

All: WebalizerWebalizer: Webalizer.o Webalizer.h Hashtab.o Hashtab.h linelist.o linklist.h preserve.o preserve.h DNS_RESOLV.O DNS_RESOLV.H Parser.o Parser.h Output.o Output.h graphs.o graphs .h lang.h Webalizer_lang.h $ (cc) $ {ldflags} -o webalizer webalizer.o hashtab.o linklist.o preserve.o paser.o output.o $ {libs} rm -f Webazolver ln -s Webalizer Webazolver defines the method of compiling Webalizer target. Webalizer.o: Webalizer.c Webalizer.h Parser.h Output.h preserve.h graphs.h dns_resolv.h Webalizer_lang.h $ (cc) $ {cflags} $ {DEFS} -c Webalizer.cparser.o: Parser.c Parser.h Webalizer.h lang.h $ (cc) $ {cflags} $ {defs} -c paser.chashtab.o: Hashtab.c Hashtab.h DNS_RESOLV.H Webalizer.h lang.h $ (cc) $ {cflags} $ {defs} -c Hashtab.clinklist.o: linklist.c linklist.h Webalizer.h lang.h $ (cc) $ {cflags} $ {DEFS} -c linelist.coutput.o: Output.c output.h Webalizer.h Preserve.h Hashtab.h graphs.h lang.h $ (cc) $ {cflags} $ {defs} -c output.cpreserve.o: preserve.c preserve.h Webalizer.h Parser.h Hashtab.h graphs.h lang.h $ (Cc) $ {cflags} $ {defs} -c preserve.cdns_resolv.o: DNS_RESOLV.C DNS_RESOLV.H LANG.H Webalizer.h $ (cc) $ {cflags} $ {defs} -c DNS_RESOLV.cgraphs. O: graphs.c graphs.h Webalizer.h lang.h $ (cc) $ {cflags} $ {DEFS} -i $ {gdlib} -c graphs.c The above is the method of compiling .o files Clean: RM -F Webalizer Webazolver * .o usage * .png Daily * .png hours * .png RM -F CTRY * .png * .html * .hist * .current core * .gif Clears the compiled file distclean:

Clean RM -F Webalizer.conf * .tar * .tgz * .z * .tar.gz rm -f makefile webalizer_lang.h config.cache config.log config.status ln -s lang / webalizer_lang.english webalizer_lang.h clear compilation The file and clear some configuration files, compressed package files, and files generated by configure, which are used to make re-configure.

install: all $ (INSTALL_PROGRAM) webalizer $ {BINDIR} / webalizer $ (INSTALL_DATA) webalizer.1 $ {MANDIR} /webalizer.1 $ (INSTALL_DATA) sample.conf $ {ETCDIR} /webalizer.conf.sample rm -f $ {Bindir ln -s $ {bindir} / webazolver installer Uninstall: RM -F $ {bindir} / webalizer rm -f $ {bindir} / Webazolver RM -F $ {mandir} / Webalizer.1 RM -F $ {etcdir} /webalizer.conf.sample rm -f webalizer_lang.h ln -s language / webalizer_lang.english webalizer_lang.h Delete program We need to do it, change these two rows to use Gprof. Cflags = -wall-^ pGLDFLAGS = -pg plus a compile option -pg Next, compiler, [Webalizer-2.01-09] $ Makegcc -wall -O2 -pg -detcdir = "/ etc" -Dhave_getopt_h = 1 -DHAVE_MATH_H = 1 -C Webalizer.cgcc -wall -o2 -pg -detcdir = "/ etc" -dhave_getopt_h = 1 -DHAVE_MATH_H = 1 -C Hashtab.cgcc -wall -O2 -pg -detcdir = "/ ETC" - DHAVE_GETOPT_H = 1 -DHAVE_MATH_H = 1 -C LinkList.cgcc -wall -o2 -pg -detcdir = "/ etc" -dhave_getopt_h = 1 -DHAVE_MATH_H = 1 -c preserve.cgcc -wall-^ PPG-Detcdir = "/ ETC "-DH AVE_GETOPT_H = 1 -DHAVE_MATH_H = 1 -C DNS_RESOLV.CGCC -WALL -O2 -pg -detcdir = "/ etc" -dhave_getopt_h = 1 -DHAVE_MATH_H = 1 -C Parser.cgcc -wall-^ PRG-Detcdir = "/ etc "-Dhave_getopt_h = 1 -DHAVE_MATH_H = 1 -C output.cgcc -wall-^ pg -detcdir =" / etc "-dhave_getopt_h = 1 -DHAVE_MATH_H = 1 -i / usr / include -c graphs.cgcc -pg-p Webalizer Webalizer.o Hashtab.o LinkList.o PRESERVE.O PARSER.O OUTPUT.O DNS_RESOLV.O graphs.o -ld -lpng -lz -lm RM-F Webazolverln -s Webalizer Webazolver The following is used, remember is important One point: This information is dynamically obtained when you run, so,

If some of your programs have not been executed, the information of the part of the code cannot be obtained with the dynamic analysis tool. I have a lot of log files, a total of 12459 rows. In fact, if the number of websites is large, the number of rows of this file is very much, so the efficiency issue of Webalizer is important. [Webalizer-2.01-09] $ wc -l ../access_log 12459 ../access_log The following is to analyze this log file with Webalizer and output the result to a directory. I am using a very simple command line, and I have no use of any profile to change the default action of Webalizer, that is, this Webalizer run is in accordance with its default. [Webalizer-2.01-09] $ ./webalizer ../access_log -o ~ / Outwebalizer V2.01-09 (Linux 2.4.2-2) English logfile ../access_log (cliff) Creating Output in / export / home / ... / outHostname for reports is' example'Reading history file ... webalizer.histGenerating report for January 2002Generating summary reportSaving history information ... 12459 records in 0.66 seconds can be seen from webalizer own output, a process that file A total of 0.66 seconds. So let's take a look at the results of GPROF. After the program runs, GPROF will generate a GMON.out file in a directory. By default, it is written in the running directory of the program, but in our example, Webalizer writes the result to ../out directory, so This file is also in that directory. [Webalizer-2.01-09] $ ls ../out/gmon.out../out/gmon.out looks at its file type: [Webalizer-2.01-09] $ file ../out/gmon.out. ./out/gmon.out: GNU PROF Performance Data - Version 1 Next, we use Gprof to analyze its results, which is the result of the running of Webalizer. Since this analysis is often very long, I ordered it into a piece of gprof.out.

[Webalizer-2.01-09] $ gProf Webalizer ../out/gmon.out> gprof.out's starting time, is a list of total time spending for each function call, according to the total length of time, from high Low alignment, then according to the number of times from the number of times, finally in order of the alphabet sequence according to the function of the function, I only enumerate the previous line: Flat Profile: Each Sample Count As 0.01 Seconds.% Cumulative Self Self Total Time Seconds Seconds Calls ns / call ns / call name 26.32 0.05 0.05 main 15.79 0.08 0.03 113761 263.71 263.71 isinstr 10.53 0.10 0.02 153021 130.70 218.33 isinlist 10.53 0.12 0.02 24918 802.63 1038.75 ispage 10.53 0.14 0.02 12459 1605.27 1605.27 fmt_logrec 5.26 0.15 0.01 45968 217.54 217.54 hash 5.26 0.16 0.01 37377 267.54 267.54 unescape 5.26 0.17 0.01 12461 802.50 802.50 jdate 5.26 0.18 0.01 12459 802.63 2407.90 parse_record_web 5.26 0.19 0.01 qs_site_cmph 0.00 0.19 0.00 328172 0.00 0.00 isurlchar 0.00 0.19 0.00 66789 0.00 248.42 isinglist 0.00 0.19 0.00 24918 0.00 319.43 put_hnode 0.00 0.19 0.00 12459 0.00 0.00 parse_record 0.00 0.19 0.00 9392 0.00 0.00 PUT_INODE 0.00 0.19 0.00 9392 0.00 241.05 PUT_UNODE 0.00 0.19 0.00 8988 0.00 217.54 Find_URL 0.0 0.19 0.00 8192 0.00 0.00 from_HEX 0.00 0.19 0.00 4494 0.00 248.42 Srch_String It can be seen that the maximum cost is the main () function. We can also see from the program that the author puts a lot of processes directly in the main program. (It seems to be adjusted so that the program is more structured to modularize? , Second, the longest time consumption is Isinstr, and the number of calls is more.

Let us actually look at this function: / **************************************** ***** // * isinstr - scan for string in string * // **************************************** ************ / ISINSTR (CHAR * STR, CHAR * CP) {char * CP1, * CP2; CP1 = (CP Strlen (CP)) - 1; if (* CP == '*') {/ * if leading wildcard, start from end * / cp2 = Str Strlen (STR) -1; while ((cp1! = Cp) && (cp2! = Str)) {if (* cp1 == '*') Return 1; if (* cp1 -! = * CP2 - Return 0;} if (cp1 == cp) Return 1; Else Return 0;} else {/ * if no letting / trailing Wildcard, Just strstr * / if (* cp1! = '*') Return (str, cp)! = null); / * Otherwise do normal forward scan * / cp1 = cp; cp2 = str; while (* CP2 ! = ') {IF (* CP1 ==' * ') Return 1; if (* CP1 ! = * CP2 ) Return 0;} if (* cp1 ==' * ') Return 1; Else Return 0;} } This is a string comparison function, which can be seen from a later description, which is mainly used for the operation of the Hash table. The third function isinList is also similar to the previous function, mainly used for the operation of the Hash table.

/ *************************************************************** / / * ISINLIST - Test if string is in list * // ************************************************** ***** / char * isinList (nlistptr list, char * str) {nlistptr lptr; lptr = list; while (lptr! = null) {if (isinstr (str, lptr-> string) Return LPTR-> String LPTR = lptr-> next;} return null;} Need to pay attention to another function, ranking in the fifth: fmt_logrec / ****************** ************************* / / * FMT_LOGREC - TERMINATE LOG FIELDS W / ZEROS * / / ************ ********************************************* / VOID FMT_LOGREC (Char * Buffer) {char * cp = buffer; int q = 0, b = 0, p = 0; while (* cp! = ') {/ * break record up, terminate field with' * / switch (* cp) {case ': if (b || Q || P) Break; * cp = ''; break; case '": q ^ = 1; Break; Case' [': IF (q) Break; B ; Break; Case']: IF (Q Break; if (b> 0) B -; Break; Case '(': if (q) Break; p ; Break; Case ')': if (q) Break; IF (P> 0) P - This function is used to preprocess this line of data when the log file is processed, and this line is based on spaces. The separated rule is separated (at the same time note, although there is space in a parentheses, it cannot be divided into two columns), and each column is turned into a string ended with '' to facilitate the back program. deal with. From this data analysis result, it is necessary to improve the running efficiency of this program, shorten the runtime, and it is necessary to optimize the function of more than the time consumption. Next, another part shows the number of times the call relationship between the functions and the calling function and the time consumed by the function being called. Index% Time Self Children Called Name

[1] 94.7 0.05 0.13 main [1] 0.01 0.02 12459/12459 parse_record_web [4] 0.02 0.01 124591/153021 isinlist [2] 0.02 0.01 24918/24918 ispage [5] 0.00 0.02 62295/66789 isinglist [7] 0.01 0.00 37377 / 37377 unescape [9] 0.01 0.00 12460/12461 jdate [10] 0.00 0.01 24918/24918 put_hnode [12] 0.00 0.00 9392/9392 put_unode [13] 0.00 0.00 4494/4494 srch_string [15] 0.00 0.00 1/1 month_update_exit [18] 0.00 0.00 1/1 WRITE_MONTH_HTML [20] 0.00 0.00 328172/328172 Isurlchar [21] 0.00 0.00 12459/9392 PARSE_RECORD [22] 0.00 0.00 9392/9392 PUT_INODE [23] 0.00 0.00 14/14 Add_GList [27] 0.00 0.00 3/3 Add_nlist [31] 0.00 0.00 3/3 Tot_Visit [33] 0.00 0.00 1/1 init_counters [47] 0.00 0.00 1/1 get_history [45] 0.00 0 .00 1/1 del_hlist [44] 0.00 0.00 1/1 Write_main_index [58] 0.00 0.00 1/1 PUT_HISTORY [56] ----------------------- ------------------------ 0.00 0.00 483/153021 PUT_UNODE [13] 0.00 0.00 998/153021 PUT_HNODE [12] 0.00 0.00 26949/153021 ISPAGE [5 ] 0.02 0.01 124591/153021 main [1] [2] 17.6 0.02 0.01 153021 isinList [2] 0.01 0.00 50845/113761 isinstr [3] ------------------------------------------------------------------------------------------------ --------------------------- 0.01 0.00 50845/113761 isinList [2] 0.02 0.00 62916/113761 IsingList [7] [3] 15.8 0.03 0.00 113761 Isinstr [3] -------------------------------------------------------------------------------------------------------------------------------------------------- --- 0.01 0.02 12459/12459 Main [1] [4] 15.8 0.01 0

.02 12459 PARSE_RECORD_WEB [4] 0.02 0.00 12459/12459 FMT_LogRec [6] ---------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------- 0.02 0.01 24918/24918 Main [1] [5] 13.6 0.02 0.01 24918 ISPAGE [5] 0.00 0.00 26949/153021 isinList [2] -------- --------------------------------------- 0.02 0.00 12459/12459 Parse_Record_Web [4] [6 ] 10.5 0.02 0.00 12459 FMT_LogRec [6] --------------------------------------------------------------------------------------------------------------------- ------ 0.00 0.00 4494/66789 srch_string [15] 0.00 0.02 62295/66789 main [1] [7] 8.7 0.00 0.02 66789 IsingList [7] 0.02 0.00 62916/113761 isinstr [3] ------ ----------------------------------------- 0.00 0.00 467/45968 Update_ENTRY [17] 0.00 0.00 614/45968 Update_Exit [16] 0.00 0.00 8988/45968 Find_url [14] 0.00 0.00 9922/45968 PUT_UNODE [13] 0.01 0.00 25977/45968 PUT_HNODE [12] [8] 5.3 0.01 0.00 45968 Hash [8] --- ------------------ -------------------------- 0.01 0.00 37377/37377 Main [1] [9] 5.3 0.01 0.00 37377 Unescape [9] 0.00 0.00 8192 / 8192 from_hex [24] --------------------------------------------- - (below, in order to save space, slightly) This segment analysis result report shows the call relationship between functions, and the time of consumption, the time to consume, and the number of calls. Each function has an index value to represent (this is described later), and the time displayed by the function and the function consumed by the function of the function showed the time consumed by the function, Children showed the function called. The function consumes the time, the called shows the number of times the function calls the corresponding subunies, and the NAME displays the name of the function. At the end of the report, there is a table that lists all functions and its INDEX correspondence. This table allows you to quickly find the corresponding function in the report. Index by function name [27] add_glist [10] jdate [56] put_history [31] add_nlist [48] load_agent_array [12] put_hnode [34] calc_arc [49] load_ident_array [23] put_inode [29] cur_time [50] load_ref_array [13

] Put_unode [42] daily_total_table [35] load_site_array [11] qs_site_cmph [43] day_graph3 [51] load_srch_array [15] srch_string [44] del_hlist [36] load_url_array [57] top_ctry_table [14] find_url [1] main [37] top_entry_table [6] fmt_logrec [19] month_graph6 [38] top_sites_table [24] from_hex [52] month_links [39] top_urls_table [45] get_history [53] month_total_table [33] tot_visit [8] hash [18] month_update_exit [9] unescape [46 ] hourly_total_table [28] new_glist [17] update_entry [47] init_counters [25] new_hnode [16] update_exit [30] init_graph [32] new_nlist [40] write_html_head [7] isinglist [26] new_unode [41] write_html_tail [2] isinlist [54] open_out_file [58] write_main_index [3] isinstr [22] parse_record [20] write_month_html [5] ispage [4] parse_record_web [59] year_graph6x [21] isurlchar [55] pie_chart according to the report, in conjunction with the foregoing the ctags, We can read this program relatively clear. For other details of GPROF, you can refer to Man Page and practice your own experience. Ok, how to analyze the source code with two ways to use static and dynamic, below, for a program Output.c in the program of Webalizer. (This program I didn't involve in the previous article, because in the context, this file is the biggest, and the call between the functions is more complicated. Now, these tools will be more relaxed. Read it. In fact, the function in this file is called once until the end of the entire main program. In the main function, there is such a program at the end: if (Total_Rec> (TOTAL_IGNORE TOTAL_BAD)) / * DID We process any? * / {if (incremental) {if (save_state ()) / * incremental stuff * / {/ * error: unable to save current run data * / if (verbose) fprintf (stderr, "% s" , msg_data_err); unlink (state_fname);}} Month_UPDATE_EXIT (REC_TSTAMP); / * Calculate EXIT PAGES * / WRITE_MONTH_HTML (); / * Write Monthly HTML file * / write_main_index ();

/ * Write main html file * / put_history (); / * Write history * /} However, if there is a careful reader discovers, this function has appeared twice in the main () program, and the middle of the main () part appeared: / * check for month change * / if (cur_month = rec_month!) {/ * if yes, do monthly stuff * / t_visit = tot_visit (sm_htab); month_update_exit (req_tstamp); / * process exit pages * / write_month_html (); / * generate HTML for Month * / CLEAR_MONTH (); cur_month = REC_MONTH; / * UPDATED OUR FLAGS * / CUR_YEAR = REC_YEAR; F_DAY = L_DAY = REC_DAY;} However, it is obvious that this section is not executed. why? Take a look at the table that is called: 0.00 0.00 1/1 Write_Month_html [20] In fact, this function is the main function of Output.c. We started analyzing from it. INT WRITE_MONTH_HTML () {INT i; char HTML_FNAME [256]; / * filename storage all ... * / char png1_fname [32]; char PNG2_FNAME [32]; char buffer [buffs]; / * scratch buffer * / char dtitle [256]; CHAR HTITLE [256]; IF (Verbose> 1) Printf ("% S% S% D", MSG_GEN_RPT, L_MONTH [CUR_MONTH-1], CUR_YEAR); / * Update History * / i = CUR_MONTH-1 Hist_month; hist_year [i] = cur_year; hist_hit [i] = t_hit; hist_files [i] = t_file; hist_page [i] = t_page; hist_visit [i] = t_visit; hist_site [i] = t_site; Hist_xfer [i] = t_xfer / 1024; hist_fday [i] = f_day; hist_lday [i] = l_day; this section is preparing data, what is HIST_XXX this array? If you have not read other code, it is likely to be confused. Let's take a look. With ex command: ta hist_month, jump to HIST_MONTH Declimination, / * local variables * / int hist_month [12], hist_year [12]; / * arrays for monthly total * / u_long hist_hit [12]; / * Calculations : used to * / u_long hist_files [12]; / * Product Index.html * / U

_long hist_site [12]; / * THESE ARE READ AND SAVED * / DOUBLE HIST_XFER [12]; / * in the history file * / u_long hist_page [12]; u_long hist_visit [12]; this set of arrays is to store HIST values of. Then, use the VI search function to see the change of their value: in the function get_history (), void get_history () {INT I, Numfields; file * hist_fp; char buffer [buffsize]; / * first Initalize Internal Array * / For (i = 0; i <12; i ) {hist_month [i] = HIST_YEAR [I] = hist_fday [i] = hist_lday [i] = 0; hist_hit [i] = hist_files [i] = hist_site [i ] = HIST_PAGE [I] = HIST_VIST [I] = 0; HIST_XFER [I] = 0.0;} First, the numerical value of the array is 0. HIST_FP = fopen (Hist_fname, "R"); if (HIST_FP) {if (Verbose> 1) Printf ("% s% s", MSG_GET_HIST, HIST_FNAME); while ((buffer, bufsize, hist_fp))! = NULL) {i = atoi (buffer) -1; if (i> 11) {if (verbose) fprintf (stderr, "% s (mth =% D)", MSG_BAD_HIST, I 1); Continue;} / * Month # Year # requests files sites XFER firstday Lastday * / Numfields = SSCANF (Buffer, "% D% lu% lu% lu% lf% D% D% lu% lu", & hist_month [i], & hist_year [i] , & Hist_files [i], & hist_site [i], & hist_xfer [i], & hist_fday [i], & hist_lday [i], & hist_page [i], & hist_visit [i]); if (Numfields == 8) / * kludge forreading 1.20.xx history files * / {hist_page [i] = 0; HIST_VISIT [ I] = 0;}} fclo

SE (HIST_FP);} Reads data from the History file and assigns a HIST array. Another part of the associated occurrence is a PUT_HISTORY () function, written to the value in the HIST array to the History file. Void Put_History () {INT i; file * hist_fp; hist_fp = fopen (hist_fname, "w"); if (HIST_FP) {IF (Verbose> 1) Printf ("% s", msg_put_hist); for (i = 0; I <12; i ) {IF ((HIST_MONTH [I]! = 0) && (HIST_HIT [I]! = 0) {fprintf (HIST_FP, "% D% D% lu% lu% lu% .0F% D) % D% lu% lu ", hist_month [i], hist_year [i], hist_hit [i], hist_files [i], hist_site [i], hist_xfer [i], hist_fday [i], hist_lday [i], hist_page [ I], hist_lday [i], hist_page [i]);}} fclose (hist_fp); I recall the readme file provided in the Webalizer file, the History file stores the result of the last run analysis log, So the next time it takes it again. Ok, I understand the meaning of the HIST_ array, let's go back to the WRITE_MONTH_HTML () function. Use Control T to return to the last TAG, continue to read the code of the function. / * Fill in filenames * / sprintf (html_fname, "usage_% 04d% 02d% s.", Cur_year, cur_month, html_ext); sprintf (png1_fname, "daily_usage_% 04d% 02d.png", cur_year, cur_month); sprintf ( PNG2_FNAME, "Hourly_USAGE_% 04D% 02D.png", CUR_Year, CUR_MONTH); this is the file name that is ready .html. Where PNG is the name of the graphic file. / * Do URL related stuff here, sorting appropriately * / if ((a_ctr = load_url_array (NULL))) {if ((u_array = malloc (sizeof (UNODEPTR) * (a_ctr)))! = NULL) {a_ctr = load_url_array ( U_ARRAY); / * LOAD UP OUR SO

rt array * / if (ntop_urls || dump_urls) {qsort (u_array, a_ctr, sizeof (UNODEPTR), qs_url_cmph); if (ntop_urls) top_urls_table (0); / * Top URL's (by hits) * / if (dump_urls) dump_all_urls (); / * Dump urls tab file * /} if (ntop_urlsk) / * Top URL's (by kbytes) * / {QSort (u_Array, a_ctr, sizeof (undeptr), QS_URL_CMPK; TOP_URLS_TABLE (1);} if (NtOP_entry ) / * Top Entry Pages * / {qsort (u_array, a_ctr, sizeof (UNODEPTR), qs_url_cmpn); top_entry_table (0);} if (ntop_exit) / * Top Exit Pages * / {qsort (u_array, a_ctr, sizeof (UNODEPTR ), qs_url_cmpx; top_entry_table (1);} free (u_Array);} else if (verbose) fprintf (stderr, "% s [u_ARRAY], MSG_NOMEM_TU); / * err * /} This section is ready in Main ( The data obtained from the file from the file, copy these arrays. It is mainly necessary to read the meaning of load_url_array (). Below, use: ta loading_url_array, jump to the function. u_long load_url_array (undeptr * Pointer) {undeptr Uptr; INT i; u_long ctr = 0; / * load the array * / for (i = 0; i Next }}} Return ctr; / * Return Number loaded * /} This program is small, but it performs two different actions, depending on the Pointer parameter. If Pointer is NULL, then it counts the number of elements in um_htab this Hash table and returns a number. If Pointer is not null, copy the elements in the Hash table pointed to the Pointer to Pointer to the Pointer, and return to the total number of copied elements. Control T, return to the place just, continue to read. IF ((u_Array = Malloc (a_ctr))))! = null) {a_ctr = load_url_array (u_ARRAY); / * Load Up Our Sort array * / After counting, it is U_Array allocated space, It is possible to install all the elements in um_htab, then

Copy all the elements in um_htab to the space pointed to by U_ARRAY, and then, / * do url related stuff here, sorting appriately * / if ((a_ctr = load_url_array (null)) {if ((u_ARRAY = ! malloc (sizeof (UNODEPTR) * (a_ctr))) = NULL) {a_ctr = load_url_array (u_array); / * load up our sort array * / if (ntop_urls '' dump_urls) {qsort (u_array, a_ctr, sizeof (UNODEPTR ), qs_url_cmph); if (ntop_urls) TOP_URLS_TABLE (0); / * TOP URL's (By Hits) * / if (Dump_URLS) Dump_all_URLS (); / * Dump Urls Tab File * /} If (Ntop_urlsk) / * TOP URL'S ( by kbytes) * / {qsort (u_array, a_ctr, sizeof (UNODEPTR), qs_url_cmpk); top_urls_table (1);} if (ntop_entry) / * Top Entry Pages * / {qsort (u_array, a_ctr, sizeof (UNODEPTR), qs_url_cmpn ); TOP_ENTRY_TABLE (0);} if (ntop_exit) / * TOP EXIT PAGES * / {QSORT (U_Array, A_CTR, SIZEOF (UNODEPTR), QS_URL_CMPX); TOP_ENTRY_TABLE (1);} Free (u_Array);} else} ) fprintf (stderr, "% s [u_ARRAY]", MSG_NOMEM_TU); / * Err * /} / * do hostname (Sites) related stuff here, sorting appropriately ... * / if ((a_ctr = load_site_array (NULL))) {if ((h_array = malloc (sizeof (HNODEPTR) * (a_ctr)))! = NULL) {a_ctr = load_site_array (h_array ); / * load Up Our sort array * / if (ntop_sites '' dump_sites) {Qsort (H_Array, A_CTR, SIZEOF (HNODEPTR), QS_SITE_CMPH); if (Ntop_SITES) TOP_SITES_TABLE (0); / * Top Sites Table (by Hits * / If (dump_sites) dump_all_sites (); / * dump sites tab file * /} if (ntop_sitesk) / * Top Sites table (by kbytes) * / {QSort (h_array, a_ctr, sizeof (hnodeptr), qs_site_cmpk; TOP_SITES_TABLE (1);} free (h_array);} else if (verbose) fprintf (s

Tderr, "% s [h_array]", msg_nomem_ts); / * err * /} Sort by QSORT function. This function sorts U_ARRAY based on the last parameter (this is a function pointer). The function pointer points to the function indicates the standard, for example, with an integer that is less than, equal to 0, to indicate that the two elements are less than, equal to, greater than the relationship. After sorting, or output a part of element (such as TOP_SITES_TABLE ()) or outputs all elements (Dump_all_urls ()). Here, we are more interested in the last parameters of the QSort function, notice that there are many such a larger function, we start from qs_url_cmph (). Use: TA Qs_URL_CMPH to the function. / ****************************************************** / / * QS_URL_CMPH - qsort compare url by hits * // *********************************************************** **** / int qs_url_cmph (const void * cp1, const void * cp2) {u_long T1, t2; t1 = (undeptr *) cp1) -> count; t2 = (* (undeptr *) CP2 -> Count; if (t1! = t2) RETURN (T2 string (* (Undepttr *) cp2) -> string);} This function is determined by the size of the two elements based on the size of the count in the undee. For convenience, we are also listed below the structural definition of undee. Struct unode {char * string; / * url hash table structure * / int flag; / * Object Type (reg, hide, grp) * / u_long count; / * requests counter * / u_long files; / * files counter * / u_long Entry; / * Entry; / * exit page counter * / double xfer; / * xfer size in bytes * / struct unode * next;}; / * Pointer to next node * // **** *************************************************** / / * QS_SITE_CMPK - QSort Cmp Site By Bytes * // ***************************************************** / INT QS_SITE_CMPK (const void * cp1, const void * cp2) {DOUBLE T1, T2; T1 = (* (hnodeptr *) CP1) -> XFER; T2 = (* (hnodeptr *) CP2) -> XFER; if (T1 ! = T2) RETURN (T2

AME, WE SORT BY HOSTNAME INST * / RETURN STRCMP (* (HnodePtr *) CP1) -> String, (* (HNODEPTR *) CP2) -> String);} This function is determined according to the size of XFER in Hnode The size of the two elements. / ****************************************************** / / * QS_URL_CMPH - qsort compare url by hits * // *********************************************************** **** / int qs_url_cmph (const void * cp1, const void * cp2) {u_long T1, t2; t1 = (undeptr *) cp1) -> count; t2 = (* (undeptr *) CP2 -> Count; if (t1! = t2) RETURN (T2 string (* (Undepttr *) cp2) -> string);} This function is determined by the size of the two elements based on the size of the count in the undee. / ***************************************************************** / / * QS_URL_CMPK - qsort compare url by bytes * // ********************************************************* **** / int qs_url_cmpk (const void * cp1, const void * cp2) {DOUBLE T1, T2; T1 = (* (undeptr *) cp1) -> xfer; t2 = (* (undeptr *) cp2) -> XFER; if (t1! = t2) RETURN (T2 String, (* (undepttr *) CP2) -> string);} This function is based on the size of the XFER in the undee to determine the size of the two elements. / ***************************************************** / / * QS_URL_CMPN - Qsort compare url by entry * // ********************************************************** **** / int qs_url_cmpn (const void * cp1, const void * cp2) {DOUBLE T1, T2; T1 = (* (undeptr *) CP1) -> Entry; T2 = (* (undeptr *) CP2 -> Entry; if (t1! = t2) RETURN (T2 String, (* (undepttr *) CP2) -> string);} This function is determined by the size of the Entry in the undee to determine the size of the two elements. / ****************************************

****** // * qs_url_cmpx - Qsort Compare URL by EXIT * / / ****************************************** ************** / INT QS_URL_CMPX (const void * cp1, const void * cp2) {DOUBLE T1, T2; T1 = (* (undeptr *) cp1) -> EXIT; T2 = (* (Undeptr *) CP2) -> EXIT; if (t1! = T2) RETURN (T2 string, (* (undepttr *) cp2) -> string);} This function is determined by the size of the EXIT in the undee to determine the size of the two elements. / ****************************************************** / / * QS_REF_CMPH - qsort compare refs by hits * // ************************************************* **** / int qs_ref_cmph (const void * cp1, const void * cp2) {u_long t1, t2; t1 = (* (RNODEPTR *) CP1) -> count; t2 = (* (RnodePtr *) CP2 -> Count; if (t1! = t2) RETURN (T2 String, (* (RNODEPTR *) CP2) -> String);} This function is determined by the size of the count in RNODE to determine the size of the two elements. / ****************************************************** / / * QS_AGNT_CMPH - Qsort Cmp Agents by Hits * // ********************************************************** **** / INT QS_AGNT_CMPH (const void * cp1, const void * cp2) {u_long t1, t2; t1 = (* (anodeptr *) cp1) -> count; t2 = (* (anodeptr *) CP2 -> Count; if (t1! = t2) RETURN (T2 String, (* (anodeptr *) CP2) -> string);} This function is determined by the size of the count in anode to determine the size of the two elements. / ******************************************************* / / * qs_srch_cmph - Qsort Cmp Srch str by hits * // ******************************************************** ***** / int qs_srch_cmph (const void * cp1, const void * cp2) {u_long t1, t2; t1 = (* (SnodePtr

*) CP1) -> count; t2 = (* (snodeptr *) CP2) -> count; if (t1! = t2) RETURN (T2 String, (* (SnodePtr *) CP2) -> string);} This function is determined by the size of the count in the SNODE. The size of the element. / ******************************************************* / / * QS_IDENT_CMPH - Qsort Cmp Ident By Hits * // ************************************************** **** / int qs_ident_cmph (const void * cp1, const void * cp2) {u_long t1, t2; t1 = (* (inodeptr *) cp1) -> count; t2 = (* (inodeptr *) cp2) -> Count; if (t1! = t2) RETURN (T2 String, (* (inodeptr *) CP2) -> string);} This function is determined by the size of the count in Inode to determine the size of the two elements. The analysis is clearly these functions, and the work below is much easier. Because for each Hash table, such as unode, snote, etc., there is a set of functions, load_xxx_array, and corresponding QSort and its relatively large functions, the following program code segment is just a set of each data. New treatment methods are essentially the same. For example, / * do hostname (sites) Related stuff here, sorting appropriately ... * / if ((a_ctr = load_site_array (null)) {if ((h_array = malloc (sizeof (hnodeptr) * (a_ctr))))! = NULL) {a_ctr = load_site_array (h_array); / * load up our sort array * / if (ntop_sites '' dump_sites) {qsort (h_array, a_ctr, sizeof (HNODEPTR), qs_site_cmph); if (ntop_sites) top_sites_table (0) ; / * TOP SITES TABLE (BY HITS) * / if (Dump_SITES) Dump_all_sites (); / * Dump Sites Tab File * /} If (Ntop_sitesk) / * Top Sites Table (BY KBYTES) * / {Qsort (h_array, a_ctr , sizeof (hnodeptr), qs_site_cmpk; Top_sites_table (1);} free (h_array);} else if (verbose) fprintf (stderr, "% s [h_arr

转载请注明原文地址:https://www.9cbs.com/read-64050.html

New Post(0)