Rewrite Cachegrind docs.

For all the changes I've made recently. And also various other changes
that occurred over the past 20 years that didn't previously make it into
the docs.

Also, this change de-emphasises the cache and branch simulation aspect,
because they're no longer that useful. Instead it emphasises the
precision and reproducibility of instruction count profiling.
This commit is contained in:
Nicholas Nethercote 2023-04-21 07:20:11 +10:00
parent 24932ed449
commit c2e62127ad
7 changed files with 7489 additions and 819 deletions

File diff suppressed because it is too large Load Diff

View File

@ -30,8 +30,9 @@
<refsect1 id="cg_annotate-description">
<title>Description</title>
<para><command>cg_annotate</command> takes an output file produced by the
Valgrind tool Cachegrind and prints the information in an easy-to-read form.
<para>
<command>cg_annotate</command> takes one or more Cachegrind output files and
prints data about the profiled program in an easy-to-read form.
</para>
</refsect1>

View File

@ -14,7 +14,7 @@
<refnamediv>
<refname>cg_diff</refname>
<refpurpose>compares two Cachegrind output files</refpurpose>
<refpurpose>(deprecated) diffs two Cachegrind output files</refpurpose>
</refnamediv>
<refsynopsisdiv>
@ -30,9 +30,10 @@
<refsect1 id="cg_diff-description">
<title>Description</title>
<para><command>cg_diff</command> takes two output files produced by the
Valgrind tool Cachegrind, computes the difference and prints the result
in the same format that Cachegrinds outputs.
<para>
<command>cg_diff</command> diffs two Cachegrind output files into a single
Cachegrind output file. It is deprecated because <command>cg_annotate</command>
can now do much the same thing, but better.
</para>
</refsect1>

View File

@ -14,7 +14,7 @@
<refnamediv>
<refname>cg_merge</refname>
<refpurpose>merges multiple Cachegrind output files into one</refpurpose>
<refpurpose>(deprecated) merges multiple Cachegrind output files into one</refpurpose>
</refnamediv>
<refsynopsisdiv>
@ -29,8 +29,10 @@
<refsect1 id="cg_merge-description">
<title>Description</title>
<para><command>cg_merge</command> sums together the outputs of multiple
Cachegrind runs into a single output file.
<para>
<command>cg_merge</command> sums together multiple Cachegrind output files into
a single Cachegrind output file. It is deprecated because
<command>cg_annotate</command> can now do much the same thing, but better.
</para>
</refsect1>

532
cachegrind/docs/concord.c Normal file
View File

@ -0,0 +1,532 @@
/********************************************************************************
** Program: concord.c
** By: Nick Nethercote, 36448. Any code taken from elsewhere as noted.
** For: 433-253 assignment 3.
**
** Program description: This program is a tool for finding specific
** occurrences of words in a text; it can count the number of times a single
** word appears, or list the lines that a word, or multiple words, all appear
** on. See the project specification for more detail.
** The primary data structure used is a static hash table, of fixed size.
** Any collisions of words hashing to the same position in the table are
** dealt with via separate chaining. Also, for each word, there is a
** subsidiary linked list containing the line numbers that the word appears on.
** Thus there are linked lists within linked lists.
** I have implemented the entire program within one file, partly because
** there isn't a great deal of code, and partly because I haven't yet done
** 433-252, and thus don't know a great deal about .h files, makefiles, etc.
*/
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#define TRUE 1
#define FALSE 0
#define MAX_WORD_LENGTH 100
#define DUMMY_WORD_LENGTH 2
#define TABLE_SIZE 997
#define BEFORE_WORD 1
#define IN_WORD 2
#define AFTER_WORD 3
#define HASH_CONSTANT 256
#define ARGS_NUMBER 1
typedef struct word_node Word_Node;
typedef struct line_node Line_Node;
typedef struct word_info Word_Info;
typedef struct arg_node Arg_Node;
/* Linked list node for storing each word */
struct word_node {
char *word; /* The actual word */
int number; /* The number of occurrences */
Line_Node *line_list; /* Points to the linked list of line numbers */
Line_Node *last_line; /* Points to the last line node, for easy append */
Word_Node *next_word; /* Next node in list */
};
/* Subsidiary linked list node for storing line numbers */
struct line_node {
int line;
Line_Node *next_line;
};
/* Structure used when reading each word, and it line number, from file. */
struct word_info {
char word[MAX_WORD_LENGTH];
int line;
};
/* Linked list node used for holding multiple arguments from the program's
** internal command line. Also, can point to a list of line numbers; this
** is used when displaying line numbers.
*/
struct arg_node {
char *word;
Line_Node *line_list;
Arg_Node *next_arg;
};
int hash(char *word);
void *create(int mem_size);
void init_hash_table(char *file_name, Word_Node *table[]);
int get_word(Word_Info *data, int line, FILE *file_ptr);
void insert(char *inword, int in_line, Word_Node *table[]);
Word_Node *new_word_node(char *inword, int in_line);
Line_Node *add_existing(Line_Node *curr, int in_line);
void interact(Word_Node *table[]);
Arg_Node *place_args_in_list(char command[]);
Arg_Node *append(char *word, Arg_Node *head);
void count(Arg_Node *head, Word_Node *table[]);
void list_lines(Arg_Node *head, Word_Node *table[]);
void intersection(Arg_Node *head);
void intersect_array(int master[], int size, Arg_Node *arg_head);
void kill_arg_list(Arg_Node *head);
int main(int argc, char *argv[])
{
/* The actual hash table, a fixed-size array of pointers to word nodes */
Word_Node *table[TABLE_SIZE];
/* Checking command line input for one file name */
if (argc != ARGS_NUMBER + 1) {
fprintf(stderr, "%s requires %d argument\n", argv[0], ARGS_NUMBER);
exit(EXIT_FAILURE);
}
init_hash_table(argv[1], table);
interact(table);
/* Nb: I am not freeing the dynamic memory in the hash table, having been
** told this is not necessary. */
return 0;
}
/* General dynamic allocation function that allocates and then checks. */
void *create(int mem_size)
{
void *dyn_block;
dyn_block = malloc(mem_size);
if (!(dyn_block)) {
fprintf(stderr, "Couldn't allocate enough memory to continue.\n");
exit(EXIT_FAILURE);
}
return dyn_block;
}
/* Function returns a hash value on a word. Almost identical to the hash
** function presented in Sedgewick.
*/
int hash(char *word)
{
int hash_value = 0;
for ( ; *word; word++)
hash_value = (HASH_CONSTANT * hash_value + *word) % TABLE_SIZE;
return hash_value;
}
/* Function builds the hash table from the given file. */
void init_hash_table(char *file_name, Word_Node *table[])
{
FILE *file_ptr;
Word_Info *data;
int line = 1, i;
/* Structure used when reading in words and line numbers. */
data = (Word_Info *) create(sizeof(Word_Info));
/* Initialise entire table to NULL. */
for (i = 0; i < TABLE_SIZE; i++)
table[i] = NULL;
/* Open file, check it. */
file_ptr = fopen(file_name, "r");
if (!(file_ptr)) {
fprintf(stderr, "Couldn't open '%s'.\n", file_name);
exit(EXIT_FAILURE);
}
/* 'Get' the words and lines one at a time from the file, and insert them
** into the table one at a time. */
while ((line = get_word(data, line, file_ptr)) != EOF)
insert(data->word, data->line, table);
free(data);
fclose(file_ptr);
}
/* Function reads the next word, and it's line number, and places them in the
** structure 'data', via a pointer.
*/
int get_word(Word_Info *data, int line, FILE *file_ptr)
{
int index = 0, pos = BEFORE_WORD;
/* Only alphabetic characters are read, apostrophes are ignored, and other
** characters are considered separators. 'pos' helps keep track whether
** the current file position is inside a word or between words.
*/
while ((data->word[index] = tolower(fgetc(file_ptr))) != EOF) {
if (data->word[index] == '\n')
line++;
if (islower(data->word[index])) {
if (pos == BEFORE_WORD) {
pos = IN_WORD;
data->line = line;
}
index++;
}
else if ((pos == IN_WORD) && (data->word[index] != '\'')) {
break;
}
}
/* Signals end of file has been reached. */
if (data->word[index] == EOF)
line = EOF;
/* Adding the null character. */
data->word[index] = '\0';
return line;
}
/* Function inserts a word and it's line number into the hash table. */
void insert(char *inword, int in_line, Word_Node *table[])
{
int position = hash(inword);
Word_Node *curr, *prev = NULL;
char dummy_word[DUMMY_WORD_LENGTH] = "A";
/* The case where that hash position hasn't been used before; a new word
** node is created.
*/
if (table[position] == NULL)
table[position] = new_word_node(dummy_word, 0);
curr = table[position];
/* Traverses that position's list of words until the current word is found
** (i.e. it's come up before) or the list end is reached (i.e. it's the
** first occurrence of the word).
*/
while ((curr != NULL) && (strcmp(inword, curr->word) > 0)) {
prev = curr;
curr = curr->next_word;
}
/* If the word hasn't appeared before, it's inserted alphabetically into
** the list.
*/
if ((curr == NULL) || (strcmp(curr->word, inword) != 0)) {
prev->next_word = new_word_node(inword, in_line);
prev->next_word->next_word = curr;
}
/* Otherwise, the word count is incremented, and the line number is added
** to the existing list.
*/
else {
(curr->number)++;
curr->last_line = add_existing(curr->last_line, in_line);
}
}
/* Function creates a new node for when a word is inserted for the first time.
*/
Word_Node *new_word_node(char *inword, int in_line)
{
Word_Node *new;
new = (Word_Node *) create(sizeof(Word_Node));
new->word = (char *) create(sizeof(char) * (strlen(inword) + 1));
new->word = strcpy(new->word, inword);
/* The word count is set to 1, as this is the first occurrence! */
new->number = 1;
new->next_word = NULL;
/* One line number node is added. */
new->line_list = (Line_Node *) create(sizeof(Line_Node));
new->line_list->line = in_line;
new->line_list->next_line = NULL;
new->last_line = new->line_list;
return new;
}
/* Function adds a line number to the line number list of a word that has
** already been inserted at least once. The pointer 'last_line', part of
** the word node structure, allows easy appending to the list.
*/
Line_Node *add_existing(Line_Node *last_line, int in_line)
{
/* Check to see if that line has already occurred - multiple occurrences on
** the one line are only recorded once. (Nb: They are counted twice, but
** only listed once.)
*/
if (last_line->line != in_line) {
last_line->next_line = (Line_Node *) create(sizeof(Line_Node));
last_line = last_line->next_line;
last_line->line = in_line;
last_line->next_line = NULL;
}
return last_line;
}
/* Function controls the interactive command line part of the program. */
void interact(Word_Node *table[])
{
char args[MAX_WORD_LENGTH]; /* Array to hold command line */
Arg_Node *arg_list = NULL; /* List that holds processed arguments */
int not_quitted = TRUE; /* Quit flag */
/* The prompt (?) is displayed. Commands are read into an array, and then
** individual arguments are placed into a linked list for easy use.
** The first argument (actually the command) is looked at to determine
** what action should be performed. 'arg_list->next_arg' is passed to
** count() and list_lines(), because the actual 'c' or 'l' is not needed
** by them. Lastly, the argument linked list is freed, by 'kill_arg_list'.
*/
do {
printf("?");
fgets(args, MAX_WORD_LENGTH - 1, stdin);
arg_list = place_args_in_list(args);
if (arg_list) {
if (strcmp(arg_list->word, "c") == 0)
count(arg_list->next_arg, table);
else if (strcmp(arg_list->word, "l") == 0)
list_lines(arg_list->next_arg, table);
else if (strcmp(arg_list->word, "q") == 0) {
printf("Quitting concord\n");
not_quitted = FALSE;
}
else
printf("Not a valid command.\n");
kill_arg_list(arg_list);
}
} while (not_quitted); /* Quits on flag */
}
/* Function takes an array containing a command line, and parses it, placing
** actual word into a linked list.
*/
Arg_Node *place_args_in_list(char command[])
{
int index1 = 0, index2 = 0, pos = BEFORE_WORD;
char token[MAX_WORD_LENGTH], c;
Arg_Node *head = NULL;
/* Non alphabetic characters are discarded. Alphabetic characters are
** copied into the array 'token'. Once the current word has been copied
** into 'token', 'append' is called, copying 'token' to a new node in the
** linked list.
*/
while (command[index1] != '\0') {
c = tolower(command[index1++]);
if (islower(c)) {
token[index2++] = c;
pos = IN_WORD;
}
else if (c == '\'')
token[index2] = c;
else if (pos == IN_WORD) {
pos = BEFORE_WORD;
token[index2] = '\0';
head = append(token, head);
index2 = 0;
}
}
return head;
}
/* Function takes a word, and appends a new node containing that word to the
** list.
*/
Arg_Node *append(char *word, Arg_Node *head)
{
Arg_Node *curr = head,
*new = (Arg_Node *) create(sizeof(Arg_Node));
new->word = (char *) create(sizeof(char) * (strlen(word) + 1));
strcpy(new->word, word);
new->line_list = NULL;
new->next_arg = NULL;
if (head == NULL)
return new;
while (curr->next_arg != NULL)
curr = curr->next_arg;
curr->next_arg = new;
return head;
}
/* Function displays the number of times a word has occurred. */
void count(Arg_Node *arg_list, Word_Node *table[])
{
int hash_pos = 0; /* Only initialised to avoid gnuc warnings */
Word_Node *curr_word = NULL;
/* Checking for the right number of arguments (one). */
if (arg_list) {
if (arg_list->next_arg != NULL) {
printf("c requires only one argument\n");
return;
}
hash_pos = hash(arg_list->word);
}
else
return;
/* Finds if the supplied word is in table, firstly by hashing to it's
** would be position, and then traversing the list of words. If present,
** it's number is displayed, otherwise '0' is printed.
*/
if (table[hash_pos]) {
curr_word = table[hash_pos]->next_word;
while ((curr_word != NULL) &&
(strcmp(arg_list->word, curr_word->word) != 0))
curr_word = curr_word->next_word;
if (curr_word)
printf("%d\n", curr_word->number);
else
printf("0\n");
}
else
printf("0\n");
}
/* Function that takes each node in the argument list, and directs a pointer
** to that word's list of lines, which are present in the hash table.
*/
void list_lines(Arg_Node *arg_head, Word_Node *table[])
{
int hash_pos = 0; /* Only initialised to avoid gnuc warnings */
Word_Node *curr_word;
Arg_Node *curr_arg = arg_head;
/* For each word in the list of arguments, the word is looked for in the
** hash table. Each argument node has a pointer, and if the word is there,
** that pointer is set to point at that word's list of line numbers.
*/
while (curr_arg != NULL) {
hash_pos = hash(curr_arg->word);
if (table[hash_pos]) {
curr_word = table[hash_pos]->next_word; /* Gets past dummy node */
while (curr_word != NULL &&
strcmp(curr_arg->word, curr_word->word) != 0)
curr_word = curr_word->next_word;
if (curr_word)
curr_arg->line_list = curr_word->line_list;
}
curr_arg = curr_arg->next_arg;
}
/* An intersection is then performed, to determine which lines, if any,
** all the arguments appear on.
*/
if (arg_head)
intersection(arg_head);
}
/* Function takes a list of line lists, and finds the lines that are common
** to each line list, by using a comparison array.
*/
void intersection(Arg_Node *arg_head)
{
Line_Node *curr_line;
int *master, n = 0, index = 0, output = FALSE;
/* Find size of first list, for creating master array */
curr_line = arg_head->line_list;
while (curr_line) {
n++;
curr_line = curr_line->next_line;
}
/* The master comparison array is created. */
master = (int *) create(sizeof(int) * n);
curr_line = arg_head->line_list;
/* Copy first list into master array */
while (curr_line) {
*(master + index++) = curr_line->line;
curr_line = curr_line->next_line;
}
/* Perform the actual intersection. */
intersect_array(master, n, arg_head->next_arg);
/* Print the line numbers left in the processed array, those left contain
** all the words specified in the command.
*/
for (index = 0; index < n; index++)
if (*(master + index) != 0) {
printf("%d ", *(master + index));
output = TRUE;
}
/* 'Output' merely prevents an unnecessary newline when 'l' returns no
** answer.
*/
if (output)
printf("\n");
/* Deallocate dynamic memory for master array */
free(master);
}
/* Function takes master array containing line numbers - these depend on the
** first list of lines, and is done in 'list_lines'. It then moves through the
** argument list. For each word, each line number in master is compared to each
** line number in that word's line list. If there is no match, then that
** position in the array is set to 0, because that line is no longer in
** contention as an answer.
*/
void intersect_array(int master[], int size, Arg_Node *arg_head)
{
int index = 0;
Line_Node *curr_line;
while (arg_head) {
index = 0;
curr_line = arg_head->line_list;
/* For each line in the list, any number less than that in the array will
** be set to zero. Any number equal to that in the list will remain.
** This loop depends on the fact that both the line list, and the master
** array, are sorted. */
while (curr_line) {
while (*(master + index) < curr_line->line && index < size)
*(master + index++) = 0;
while (*(master + index) <= curr_line->line && index < size)
index++;
curr_line = curr_line->next_line;
}
/* Once the list of lines has been traversed, any array positions that
** haven't been examined are set to zero, as they are no longer in
** contention.
*/
for ( ; index < size; index++)
*(master + index) = 0;
arg_head = arg_head->next_arg;
}
}
/* Function to free dynamic memory used by the arguments linked list. */
void kill_arg_list(Arg_Node *head)
{
Arg_Node *temp;
while (head != NULL) {
temp = head;
head = head->next_arg;
free(temp->word);
free(temp);
}
}

View File

@ -0,0 +1,560 @@
--------------------------------------------------------------------------------
-- Metadata
--------------------------------------------------------------------------------
Invocation: ../cg_annotate concord.cgout
Command: ./concord ../cg_main.c
Events recorded: Ir
Events shown: Ir
Event sort order: Ir
Threshold: 0.1%
Annotation: on
--------------------------------------------------------------------------------
-- Summary
--------------------------------------------------------------------------------
Ir________________
8,195,056 (100.0%) PROGRAM TOTALS
--------------------------------------------------------------------------------
-- File:function summary
--------------------------------------------------------------------------------
Ir______________________ file:function
< 3,078,746 (37.6%, 37.6%) /home/njn/grind/ws1/cachegrind/docs/concord.c:
1,630,232 (19.9%) get_word
630,918 (7.7%) hash
461,095 (5.6%) insert
130,560 (1.6%) add_existing
91,014 (1.1%) init_hash_table
88,056 (1.1%) create
46,676 (0.6%) new_word_node
< 1,746,038 (21.3%, 58.9%) ./malloc/./malloc/malloc.c:
1,285,938 (15.7%) _int_malloc
458,225 (5.6%) malloc
< 1,107,550 (13.5%, 72.4%) ./libio/./libio/getc.c:getc
< 551,071 (6.7%, 79.1%) ./string/../sysdeps/x86_64/multiarch/strcmp-avx2.S:__strcmp_avx2
< 521,228 (6.4%, 85.5%) ./ctype/../include/ctype.h:
260,616 (3.2%) __ctype_tolower_loc
260,612 (3.2%) __ctype_b_loc
< 468,163 (5.7%, 91.2%) ???:
468,151 (5.7%) ???
< 456,071 (5.6%, 96.8%) /usr/include/ctype.h:get_word
< 48,344 (0.6%, 97.3%) ./string/../sysdeps/x86_64/multiarch/strcpy-avx2.S:__strcpy_avx2
< 40,776 (0.5%, 97.8%) ./elf/./elf/dl-lookup.c:
25,623 (0.3%) do_lookup_x
9,515 (0.1%) _dl_lookup_symbol_x
< 37,412 (0.5%, 98.3%) ./elf/./elf/dl-tunables.c:
36,500 (0.4%) __GI___tunables_init
< 23,366 (0.3%, 98.6%) ./string/../sysdeps/x86_64/multiarch/strlen-avx2.S:__strlen_avx2
< 22,107 (0.3%, 98.9%) ./malloc/./malloc/arena.c:
22,023 (0.3%) malloc
< 16,539 (0.2%, 99.1%) ./elf/./elf/dl-reloc.c:_dl_relocate_object
< 9,160 (0.1%, 99.2%) ./elf/../sysdeps/generic/dl-new-hash.h:_dl_lookup_symbol_x
< 8,535 (0.1%, 99.3%) ./string/../sysdeps/x86_64/multiarch/../multiarch/strcmp-sse2.S:
8,503 (0.1%) strcmp
--------------------------------------------------------------------------------
-- Function:file summary
--------------------------------------------------------------------------------
Ir______________________ function:file
> 2,086,303 (25.5%, 25.5%) get_word:
1,630,232 (19.9%) /home/njn/grind/ws1/cachegrind/docs/concord.c
456,071 (5.6%) /usr/include/ctype.h
> 1,285,938 (15.7%, 41.1%) _int_malloc:./malloc/./malloc/malloc.c
> 1,107,550 (13.5%, 54.7%) getc:./libio/./libio/getc.c
> 630,918 (7.7%, 62.4%) hash:/home/njn/grind/ws1/cachegrind/docs/concord.c
> 551,071 (6.7%, 69.1%) __strcmp_avx2:./string/../sysdeps/x86_64/multiarch/strcmp-avx2.S
> 480,248 (5.9%, 74.9%) malloc:
458,225 (5.6%) ./malloc/./malloc/malloc.c
22,023 (0.3%) ./malloc/./malloc/arena.c
> 468,151 (5.7%, 80.7%) ???:???
> 461,095 (5.6%, 86.3%) insert:/home/njn/grind/ws1/cachegrind/docs/concord.c
> 260,616 (3.2%, 89.5%) __ctype_tolower_loc:./ctype/../include/ctype.h
> 260,612 (3.2%, 92.6%) __ctype_b_loc:./ctype/../include/ctype.h
> 130,560 (1.6%, 94.2%) add_existing:/home/njn/grind/ws1/cachegrind/docs/concord.c
> 91,014 (1.1%, 95.4%) init_hash_table:/home/njn/grind/ws1/cachegrind/docs/concord.c
> 88,056 (1.1%, 96.4%) create:/home/njn/grind/ws1/cachegrind/docs/concord.c
> 50,010 (0.6%, 97.0%) new_word_node:
46,676 (0.6%) /home/njn/grind/ws1/cachegrind/docs/concord.c
> 48,344 (0.6%, 97.6%) __strcpy_avx2:./string/../sysdeps/x86_64/multiarch/strcpy-avx2.S
> 42,906 (0.5%, 98.1%) __GI___tunables_init:
36,500 (0.4%) ./elf/./elf/dl-tunables.c
> 26,514 (0.3%, 98.5%) do_lookup_x:
25,623 (0.3%) ./elf/./elf/dl-lookup.c
> 25,642 (0.3%, 98.8%) _dl_relocate_object:
16,539 (0.2%) ./elf/./elf/dl-reloc.c
> 23,366 (0.3%, 99.1%) __strlen_avx2:./string/../sysdeps/x86_64/multiarch/strlen-avx2.S
> 18,675 (0.2%, 99.3%) _dl_lookup_symbol_x:
9,515 (0.1%) ./elf/./elf/dl-lookup.c
9,160 (0.1%) ./elf/../sysdeps/generic/dl-new-hash.h
> 8,547 (0.1%, 99.4%) strcmp:
8,503 (0.1%) ./string/../sysdeps/x86_64/multiarch/../multiarch/strcmp-sse2.S
--------------------------------------------------------------------------------
-- Annotated source file: ./ctype/../include/ctype.h
--------------------------------------------------------------------------------
Unannotated because one or more of these original files are unreadable:
- ./ctype/../include/ctype.h
--------------------------------------------------------------------------------
-- Annotated source file: ./elf/../sysdeps/generic/dl-new-hash.h
--------------------------------------------------------------------------------
Unannotated because one or more of these original files are unreadable:
- ./elf/../sysdeps/generic/dl-new-hash.h
--------------------------------------------------------------------------------
-- Annotated source file: ./elf/./elf/dl-lookup.c
--------------------------------------------------------------------------------
Unannotated because one or more of these original files are unreadable:
- ./elf/./elf/dl-lookup.c
--------------------------------------------------------------------------------
-- Annotated source file: ./elf/./elf/dl-reloc.c
--------------------------------------------------------------------------------
Unannotated because one or more of these original files are unreadable:
- ./elf/./elf/dl-reloc.c
--------------------------------------------------------------------------------
-- Annotated source file: ./elf/./elf/dl-tunables.c
--------------------------------------------------------------------------------
Unannotated because one or more of these original files are unreadable:
- ./elf/./elf/dl-tunables.c
--------------------------------------------------------------------------------
-- Annotated source file: ./libio/./libio/getc.c
--------------------------------------------------------------------------------
Unannotated because one or more of these original files are unreadable:
- ./libio/./libio/getc.c
--------------------------------------------------------------------------------
-- Annotated source file: ./malloc/./malloc/arena.c
--------------------------------------------------------------------------------
Unannotated because one or more of these original files are unreadable:
- ./malloc/./malloc/arena.c
--------------------------------------------------------------------------------
-- Annotated source file: ./malloc/./malloc/malloc.c
--------------------------------------------------------------------------------
Unannotated because one or more of these original files are unreadable:
- ./malloc/./malloc/malloc.c
--------------------------------------------------------------------------------
-- Annotated source file: ./string/../sysdeps/x86_64/multiarch/../multiarch/strcmp-sse2.S
--------------------------------------------------------------------------------
Unannotated because one or more of these original files are unreadable:
- ./string/../sysdeps/x86_64/multiarch/../multiarch/strcmp-sse2.S
--------------------------------------------------------------------------------
-- Annotated source file: ./string/../sysdeps/x86_64/multiarch/strcmp-avx2.S
--------------------------------------------------------------------------------
Unannotated because one or more of these original files are unreadable:
- ./string/../sysdeps/x86_64/multiarch/strcmp-avx2.S
--------------------------------------------------------------------------------
-- Annotated source file: ./string/../sysdeps/x86_64/multiarch/strcpy-avx2.S
--------------------------------------------------------------------------------
Unannotated because one or more of these original files are unreadable:
- ./string/../sysdeps/x86_64/multiarch/strcpy-avx2.S
--------------------------------------------------------------------------------
-- Annotated source file: ./string/../sysdeps/x86_64/multiarch/strlen-avx2.S
--------------------------------------------------------------------------------
Unannotated because one or more of these original files are unreadable:
- ./string/../sysdeps/x86_64/multiarch/strlen-avx2.S
--------------------------------------------------------------------------------
-- Annotated source file: /home/njn/grind/ws1/cachegrind/docs/concord.c
--------------------------------------------------------------------------------
Ir____________
-- line 81 ----------------------------------------
. Arg_Node *append(char *word, Arg_Node *head);
. void count(Arg_Node *head, Word_Node *table[]);
. void list_lines(Arg_Node *head, Word_Node *table[]);
. void intersection(Arg_Node *head);
. void intersect_array(int master[], int size, Arg_Node *arg_head);
. void kill_arg_list(Arg_Node *head);
.
. int main(int argc, char *argv[])
8 (0.0%) {
. /* The actual hash table, a fixed-size array of pointers to word nodes */
. Word_Node *table[TABLE_SIZE];
.
. /* Checking command line input for one file name */
2 (0.0%) if (argc != ARGS_NUMBER + 1) {
. fprintf(stderr, "%s requires %d argument\n", argv[0], ARGS_NUMBER);
. exit(EXIT_FAILURE);
. }
.
4 (0.0%) init_hash_table(argv[1], table);
2 (0.0%) interact(table);
.
. /* Nb: I am not freeing the dynamic memory in the hash table, having been
. ** told this is not necessary. */
. return 0;
7 (0.0%) }
.
. /* General dynamic allocation function that allocates and then checks. */
. void *create(int mem_size)
22,014 (0.3%) {
. void *dyn_block;
.
22,014 (0.3%) dyn_block = malloc(mem_size);
22,014 (0.3%) if (!(dyn_block)) {
. fprintf(stderr, "Couldn't allocate enough memory to continue.\n");
. exit(EXIT_FAILURE);
. }
.
. return dyn_block;
22,014 (0.3%) }
.
. /* Function returns a hash value on a word. Almost identical to the hash
. ** function presented in Sedgewick.
. */
. int hash(char *word)
7,908 (0.1%) {
7,908 (0.1%) int hash_value = 0;
.
161,292 (2.0%) for ( ; *word; word++)
453,810 (5.5%) hash_value = (HASH_CONSTANT * hash_value + *word) % TABLE_SIZE;
.
. return hash_value;
. }
.
. /* Function builds the hash table from the given file. */
. void init_hash_table(char *file_name, Word_Node *table[])
8 (0.0%) {
. FILE *file_ptr;
. Word_Info *data;
2 (0.0%) int line = 1, i;
.
. /* Structure used when reading in words and line numbers. */
3 (0.0%) data = (Word_Info *) create(sizeof(Word_Info));
.
. /* Initialise entire table to NULL. */
2,993 (0.0%) for (i = 0; i < TABLE_SIZE; i++)
997 (0.0%) table[i] = NULL;
.
. /* Open file, check it. */
4 (0.0%) file_ptr = fopen(file_name, "r");
2 (0.0%) if (!(file_ptr)) {
. fprintf(stderr, "Couldn't open '%s'.\n", file_name);
. exit(EXIT_FAILURE);
. }
.
. /* 'Get' the words and lines one at a time from the file, and insert them
. ** into the table one at a time. */
55,363 (0.7%) while ((line = get_word(data, line, file_ptr)) != EOF)
31,632 (0.4%) insert(data->word, data->line, table);
.
2 (0.0%) free(data);
2 (0.0%) fclose(file_ptr);
6 (0.0%) }
.
. /* Function reads the next word, and it's line number, and places them in the
. ** structure 'data', via a pointer.
. */
. int get_word(Word_Info *data, int line, FILE *file_ptr)
86,999 (1.1%) {
15,818 (0.2%) int index = 0, pos = BEFORE_WORD;
.
. /* Only alphabetic characters are read, apostrophes are ignored, and other
. ** characters are considered separators. 'pos' helps keep track whether
. ** the current file position is inside a word or between words.
. */
529,133 (6.5%) while ((data->word[index] = tolower(fgetc(file_ptr))) != EOF) {
. if (data->word[index] == '\n')
260,608 (3.2%) line++;
390,912 (4.8%) if (islower(data->word[index])) {
64,830 (0.8%) if (pos == BEFORE_WORD) {
15,816 (0.2%) pos = IN_WORD;
7,908 (0.1%) data->line = line;
. }
32,415 (0.4%) index++;
. }
146,702 (1.8%) else if ((pos == IN_WORD) && (data->word[index] != '\'')) {
. break;
. }
. }
. /* Signals end of file has been reached. */
. if (data->word[index] == EOF)
1 (0.0%) line = EOF;
.
. /* Adding the null character. */
15,818 (0.2%) data->word[index] = '\0';
.
. return line;
63,272 (0.8%) }
.
. /* Function inserts a word and it's line number into the hash table. */
. void insert(char *inword, int in_line, Word_Node *table[])
102,804 (1.3%) {
7,908 (0.1%) int position = hash(inword);
. Word_Node *curr, *prev = NULL;
7,908 (0.1%) char dummy_word[DUMMY_WORD_LENGTH] = "A";
.
. /* The case where that hash position hasn't been used before; a new word
. ** node is created.
. */
31,632 (0.4%) if (table[position] == NULL)
3,185 (0.0%) table[position] = new_word_node(dummy_word, 0);
7,908 (0.1%) curr = table[position];
.
. /* Traverses that position's list of words until the current word is found
. ** (i.e. it's come up before) or the list end is reached (i.e. it's the
. ** first occurrence of the word).
. */
118,384 (1.4%) while ((curr != NULL) && (strcmp(inword, curr->word) > 0)) {
. prev = curr;
28,366 (0.3%) curr = curr->next_word;
. }
.
. /* If the word hasn't appeared before, it's inserted alphabetically into
. ** the list.
. */
35,410 (0.4%) if ((curr == NULL) || (strcmp(curr->word, inword) != 0)) {
4,120 (0.1%) prev->next_word = new_word_node(inword, in_line);
1,030 (0.0%) prev->next_word->next_word = curr;
. }
. /* Otherwise, the word count is incremented, and the line number is added
. ** to the existing list.
. */
. else {
6,878 (0.1%) (curr->number)++;
27,512 (0.3%) curr->last_line = add_existing(curr->last_line, in_line);
. }
78,050 (1.0%) }
.
. /* Function creates a new node for when a word is inserted for the first time.
. */
. Word_Node *new_word_node(char *inword, int in_line)
10,002 (0.1%) {
. Word_Node *new;
.
5,001 (0.1%) new = (Word_Node *) create(sizeof(Word_Node));
8,335 (0.1%) new->word = (char *) create(sizeof(char) * (strlen(inword) + 1));
1,667 (0.0%) new->word = strcpy(new->word, inword);
. /* The word count is set to 1, as this is the first occurrence! */
1,667 (0.0%) new->number = 1;
1,667 (0.0%) new->next_word = NULL;
. /* One line number node is added. */
5,001 (0.1%) new->line_list = (Line_Node *) create(sizeof(Line_Node));
1,667 (0.0%) new->line_list->line = in_line;
1,667 (0.0%) new->line_list->next_line = NULL;
1,667 (0.0%) new->last_line = new->line_list;
.
. return new;
8,335 (0.1%) }
.
. /* Function adds a line number to the line number list of a word that has
. ** already been inserted at least once. The pointer 'last_line', part of
. ** the word node structure, allows easy appending to the list.
. */
. Line_Node *add_existing(Line_Node *last_line, int in_line)
34,390 (0.4%) {
. /* Check to see if that line has already occurred - multiple occurrences on
. ** the one line are only recorded once. (Nb: They are counted twice, but
. ** only listed once.)
. */
13,756 (0.2%) if (last_line->line != in_line) {
18,009 (0.2%) last_line->next_line = (Line_Node *) create(sizeof(Line_Node));
12,006 (0.1%) last_line = last_line->next_line;
6,003 (0.1%) last_line->line = in_line;
6,003 (0.1%) last_line->next_line = NULL;
. }
.
. return last_line;
40,393 (0.5%) }
.
. /* Function controls the interactive command line part of the program. */
. void interact(Word_Node *table[])
12 (0.0%) {
. char args[MAX_WORD_LENGTH]; /* Array to hold command line */
. Arg_Node *arg_list = NULL; /* List that holds processed arguments */
. int not_quitted = TRUE; /* Quit flag */
.
. /* The prompt (?) is displayed. Commands are read into an array, and then
. ** individual arguments are placed into a linked list for easy use.
. ** The first argument (actually the command) is looked at to determine
. ** what action should be performed. 'arg_list->next_arg' is passed to
. ** count() and list_lines(), because the actual 'c' or 'l' is not needed
. ** by them. Lastly, the argument linked list is freed, by 'kill_arg_list'.
. */
. do {
. printf("?");
. fgets(args, MAX_WORD_LENGTH - 1, stdin);
3 (0.0%) arg_list = place_args_in_list(args);
2 (0.0%) if (arg_list) {
7 (0.0%) if (strcmp(arg_list->word, "c") == 0)
. count(arg_list->next_arg, table);
6 (0.0%) else if (strcmp(arg_list->word, "l") == 0)
. list_lines(arg_list->next_arg, table);
8 (0.0%) else if (strcmp(arg_list->word, "q") == 0) {
. printf("Quitting concord\n");
1 (0.0%) not_quitted = FALSE;
. }
. else
. printf("Not a valid command.\n");
2 (0.0%) kill_arg_list(arg_list);
. }
2 (0.0%) } while (not_quitted); /* Quits on flag */
11 (0.0%) }
.
. /* Function takes an array containing a command line, and parses it, placing
. ** actual word into a linked list.
. */
. Arg_Node *place_args_in_list(char command[])
10 (0.0%) {
2 (0.0%) int index1 = 0, index2 = 0, pos = BEFORE_WORD;
. char token[MAX_WORD_LENGTH], c;
1 (0.0%) Arg_Node *head = NULL;
.
. /* Non alphabetic characters are discarded. Alphabetic characters are
. ** copied into the array 'token'. Once the current word has been copied
. ** into 'token', 'append' is called, copying 'token' to a new node in the
. ** linked list.
. */
12 (0.0%) while (command[index1] != '\0') {
8 (0.0%) c = tolower(command[index1++]);
11 (0.0%) if (islower(c)) {
3 (0.0%) token[index2++] = c;
4 (0.0%) pos = IN_WORD;
. }
2 (0.0%) else if (c == '\'')
. token[index2] = c;
2 (0.0%) else if (pos == IN_WORD) {
1 (0.0%) pos = BEFORE_WORD;
2 (0.0%) token[index2] = '\0';
4 (0.0%) head = append(token, head);
2 (0.0%) index2 = 0;
. }
. }
.
. return head;
11 (0.0%) }
.
. /* Function takes a word, and appends a new node containing that word to the
. ** list.
. */
. Arg_Node *append(char *word, Arg_Node *head)
6 (0.0%) {
. Arg_Node *curr = head,
3 (0.0%) *new = (Arg_Node *) create(sizeof(Arg_Node));
.
6 (0.0%) new->word = (char *) create(sizeof(char) * (strlen(word) + 1));
. strcpy(new->word, word);
1 (0.0%) new->line_list = NULL;
1 (0.0%) new->next_arg = NULL;
.
2 (0.0%) if (head == NULL)
. return new;
.
. while (curr->next_arg != NULL)
. curr = curr->next_arg;
. curr->next_arg = new;
.
. return head;
5 (0.0%) }
.
.
. /* Function displays the number of times a word has occurred. */
. void count(Arg_Node *arg_list, Word_Node *table[])
. {
. int hash_pos = 0; /* Only initialised to avoid gnuc warnings */
. Word_Node *curr_word = NULL;
.
-- line 375 ----------------------------------------
-- line 514 ----------------------------------------
. *(master + index) = 0;
.
. arg_head = arg_head->next_arg;
. }
. }
.
. /* Function to free dynamic memory used by the arguments linked list. */
. void kill_arg_list(Arg_Node *head)
5 (0.0%) {
. Arg_Node *temp;
.
4 (0.0%) while (head != NULL) {
. temp = head;
2 (0.0%) head = head->next_arg;
2 (0.0%) free(temp->word);
2 (0.0%) free(temp);
. }
4 (0.0%) }
.
--------------------------------------------------------------------------------
-- Annotated source file: /usr/include/ctype.h
--------------------------------------------------------------------------------
Ir____________
-- line 201 ----------------------------------------
. # define isblank(c) __isctype((c), _ISblank)
. # endif
. # endif
.
. # ifdef __USE_EXTERN_INLINES
. __extern_inline int
. __NTH (tolower (int __c))
. {
456,071 (5.6%) return __c >= -128 && __c < 256 ? (*__ctype_tolower_loc ())[__c] : __c;
. }
.
. __extern_inline int
. __NTH (toupper (int __c))
. {
. return __c >= -128 && __c < 256 ? (*__ctype_toupper_loc ())[__c] : __c;
. }
. # endif
-- line 217 ----------------------------------------
--------------------------------------------------------------------------------
-- Annotation summary
--------------------------------------------------------------------------------
Ir_______________
3,534,817 (43.1%) annotated: files known & above threshold & readable, line numbers known
0 annotated: files known & above threshold & readable, line numbers unknown
0 unannotated: files known & above threshold & two or more non-identical
4,132,126 (50.4%) unannotated: files known & above threshold & unreadable
59,950 (0.7%) unannotated: files known & below threshold
468,163 (5.7%) unannotated: files unknown

File diff suppressed because it is too large Load Diff