* Fixups to the make man page

* Minor syntax cleanups in the manual
* In non-maintainer mode set NDEBUG to disable assert()
* Performance improvements in strcache:
    Build Info			1000	2000	4000
    3.82 -g			2.61s	8.85s	33.52s
    3.82 -O2			1.90s	7.62s	27.82s
    New -g (with asserts)	1.03s	2.31s	5.79s
    New -O2 (no asserts)	0.65s	1.50s	3.52s
This commit is contained in:
Paul Smith 2011-02-21 07:30:11 +00:00
parent ae2ab76fac
commit 1454a04f81
7 changed files with 257 additions and 186 deletions

View File

@ -1,3 +1,25 @@
2011-02-21 Paul Smith <psmith@gnu.org>
* strcache.c (various): Increase performance based on comments
from Ralf Wildenhues <Ralf.Wildenhues@gmx.de>. Stop looking for
a buffer when we find the first one that fits, not the best fit.
If there is not enough free space in a buffer move it to a
separate list so we don't have to walk it again.
* make.h (NDEBUG): Turn off asserts unless maintainer mode is set.
(strcache_add_len, strcache_setbufsize): Use unsigned length/size.
* maintMakefile (AM_CPPFLAGS): Enable MAKE_MAINTAINER_MODE.
* remake.c (complain): Move translation lookups closer to use.
2011-02-13 Paul Smith <psmith@gnu.org>
* doc/make.texi: Clean up references to "static" variables and
semicolon errors. Patch from Michael Witten <mfwitten@gmail.com>.
2010-12-27 Paul Smith <psmith@gnu.org>
* make.1: Update the header/footer info in the man page.
2010-11-28 Paul Smith <psmith@gnu.org>
* read.c (record_target_var): Don't reset v if it's the same as

View File

@ -1487,11 +1487,11 @@ first (unescaped) variable reference to @var{ONEVAR} is expanded,
while the second (escaped) variable reference is simply unescaped,
without being recognized as a variable reference. Now during the
secondary expansion the first word is expanded again but since it
contains no variable or function references it remains the static
value @file{onefile}, while the second word is now a normal reference
to the variable @var{TWOVAR}, which is expanded to the value
@file{twofile}. The final result is that there are two prerequisites,
@file{onefile} and @file{twofile}.
contains no variable or function references it remains the value
@file{onefile}, while the second word is now a normal reference to the
variable @var{TWOVAR}, which is expanded to the value @file{twofile}.
The final result is that there are two prerequisites, @file{onefile}
and @file{twofile}.
Obviously, this is not a very interesting case since the same result
could more easily have been achieved simply by having both variables
@ -5846,13 +5846,13 @@ Multiple @var{target} values create a target-specific variable value for
each member of the target list individually.
The @var{variable-assignment} can be any valid form of assignment;
recursive (@samp{=}), static (@samp{:=}), appending (@samp{+=}), or
recursive (@samp{=}), simple (@samp{:=}), appending (@samp{+=}), or
conditional (@samp{?=}). All variables that appear within the
@var{variable-assignment} are evaluated within the context of the
target: thus, any previously-defined target-specific variable values
will be in effect. Note that this variable is actually distinct from
any ``global'' value: the two variables do not have to have the same
flavor (recursive vs.@: static).
flavor (recursive vs.@: simple).
Target-specific variables have the same priority as any other makefile
variable. Variables provided on the command line (and in the
@ -6512,7 +6512,9 @@ be substituted.
@cindex arguments of functions
@cindex functions, syntax of
A function call resembles a variable reference. It looks like this:
A function call resembles a variable reference. It can appear
anywhere a variable reference can appear, and it is expanded using the
same rules as variable references. A function call looks like this:
@example
$(@var{function} @var{arguments})
@ -7344,7 +7346,7 @@ The syntax of the @code{value} function is:
$(value @var{variable})
@end example
Note that @var{variable} is the @emph{name} of a variable; not a
Note that @var{variable} is the @emph{name} of a variable, not a
@emph{reference} to that variable. Therefore you would not normally
use a @samp{$} or parentheses when writing it. (You can, however, use
a variable reference in the name if you want the name not to be a
@ -7455,7 +7457,7 @@ The syntax of the @code{origin} function is:
$(origin @var{variable})
@end example
Note that @var{variable} is the @emph{name} of a variable to inquire about;
Note that @var{variable} is the @emph{name} of a variable to inquire about,
not a @emph{reference} to that variable. Therefore you would not normally
use a @samp{$} or parentheses when writing it. (You can, however, use a
variable reference in the name if you want the name not to be a constant.)
@ -7566,7 +7568,7 @@ The syntax of the @code{flavor} function is:
$(flavor @var{variable})
@end example
Note that @var{variable} is the @emph{name} of a variable to inquire about;
Note that @var{variable} is the @emph{name} of a variable to inquire about,
not a @emph{reference} to that variable. Therefore you would not normally
use a @samp{$} or parentheses when writing it. (You can, however, use a
variable reference in the name if you want the name not to be a constant.)

View File

@ -5,6 +5,9 @@
# We like mondo-warnings!
AM_CFLAGS += -Wall -Wextra -Wdeclaration-after-statement -Wshadow -Wpointer-arith -Wbad-function-cast
MAKE_MAINTAINER_MODE := -DMAKE_MAINTAINER_MODE
AM_CPPFLAGS += $(MAKE_MAINTAINER_MODE)
# I want this one but I have to wait for the const cleanup!
# -Wwrite-strings

168
make.1
View File

@ -1,49 +1,35 @@
.TH MAKE 1 "22 August 1989" "GNU" "LOCAL USER COMMANDS"
.TH MAKE 1 "27 December 2010" "GNU" "User Commands"
.SH NAME
make \- GNU make utility to maintain groups of programs
.SH SYNOPSIS
.B "make "
[
.B \-f
.I makefile
] [ options ] ... [ targets ] ...
.SH WARNING
This man page is an extract of the documentation of GNU
.IR make .
It is updated only occasionally, because the GNU project does not use nroff.
For complete, current documentation, refer to the Info file
.B make.info
which is made from the Texinfo source file
.BR make.texi .
.B make
[\fIOPTION\fR]... [\fITARGET\fR]...
.SH DESCRIPTION
.LP
The purpose of the
The
.I make
utility is to determine automatically which
pieces of a large program need to be recompiled, and issue the commands to
recompile them.
The manual describes the GNU implementation of
.IR make ,
which was written by Richard Stallman and Roland McGrath, and is
currently maintained by Paul Smith.
Our examples show C programs, since they are most common, but you can use
.I make
with any programming language whose compiler can be run with a
shell command.
utility will determine automatically which pieces of a large program need to
be recompiled, and issue the commands to recompile them. The manual describes
the GNU implementation of
.BR make ,
which was written by Richard Stallman and Roland McGrath, and is currently
maintained by Paul Smith. Our examples show C programs, since they are very
common, but you can use
.B make
with any programming language whose compiler can be run with a shell command.
In fact,
.I make
is not limited to programs.
You can use it to describe any task where some files must be
updated automatically from others whenever the others change.
.B make
is not limited to programs. You can use it to describe any task where some
files must be updated automatically from others whenever the others change.
.LP
To prepare to use
.IR make ,
.BR make ,
you must write a file called the
.I makefile
that describes the relationships among files in your program, and the
states the commands for updating each file.
In a program, typically the executable file is updated from object
files, which are in turn made by compiling source files.
that describes the relationships among files in your program, and the states
the commands for updating each file. In a program, typically the executable
file is updated from object files, which are in turn made by compiling source
files.
.LP
Once a suitable makefile exists, each time you change some source files,
this simple shell command:
@ -54,16 +40,15 @@ this simple shell command:
.sp 1
suffices to perform all necessary recompilations.
The
.I make
program uses the makefile data base and the last-modification times
of the files to decide which of the files need to be updated.
For each of those files, it issues the commands recorded in the data base.
.B make
program uses the makefile description and the last-modification times of the
files to decide which of the files need to be updated. For each of those
files, it issues the commands recorded in the makefile.
.LP
.I make
.B make
executes commands in the
.I makefile
to update
one or more target
to update one or more target
.IR names ,
where
.I name
@ -71,7 +56,7 @@ is typically a program.
If no
.B \-f
option is present,
.I make
.B make
will look for the makefiles
.IR GNUmakefile ,
.IR makefile ,
@ -90,27 +75,27 @@ listing, right near other important files such as
.IR README .)
The first name checked,
.IR GNUmakefile ,
is not recommended for most makefiles.
You should use this name if you have a makefile that is specific to GNU
.IR make ,
is not recommended for most makefiles. You should use this name if you have a
makefile that is specific to GNU
.BR make ,
and will not be understood by other versions of
.IR make .
.BR make .
If
.I makefile
is `\-', the standard input is read.
.LP
.I make
.B make
updates a target if it depends on prerequisite files
that have been modified since the target was last modified,
or if the target does not exist.
.SH OPTIONS
.sp 1
.TP 0.5i
.BR \-b , " \-m"
\fB\-b\fR, \fB\-m\fR
These options are ignored for compatibility with other versions of
.IR make .
.BR make .
.TP 0.5i
.BR \-B , " \-\-always\-make"
\fB\-B\fR, \fB\-\-always\-make\fR
Unconditionally make all targets.
.TP 0.5i
\fB\-C\fR \fIdir\fR, \fB\-\-directory\fR=\fIdir\fR
@ -126,7 +111,7 @@ previous one:
is equivalent to
.BR "\-C " /etc.
This is typically used with recursive invocations of
.IR make .
.BR make .
.TP 0.5i
.B \-d
Print debugging information in addition to normal processing.
@ -134,7 +119,7 @@ The debugging information says which files are being considered for
remaking, which file-times are being compared and with what results,
which files actually need to be remade, which implicit rules are
considered and which are applied---everything interesting about how
.I make
.B make
decides what to do.
.TP 0.5i
.BI \-\-debug "[=FLAGS]"
@ -160,7 +145,7 @@ for details on invocation of commands, and
.I m
for debugging while remaking makefiles.
.TP 0.5i
.BR \-e , " \-\-environment\-overrides"
\fB\-e\fR, \fB\-\-environment\-overrides\fR
Give variables taken from the environment precedence
over variables from makefiles.
.TP 0.5i
@ -169,7 +154,7 @@ Use
.I file
as a makefile.
.TP 0.5i
.BR \-i , " \-\-ignore\-errors"
\fB\-i\fR, \fB\-\-ignore\-errors\fR
Ignore all errors in commands executed to remake files.
.TP 0.5i
\fB\-I\fR \fIdir\fR, \fB\-\-include\-dir\fR=\fIdir\fR
@ -181,13 +166,14 @@ If several
options are used to specify several directories, the directories are
searched in the order specified.
Unlike the arguments to other flags of
.IR make ,
.BR make ,
directories given with
.B \-I
flags may come directly after the flag:
.BI \-I dir
is allowed, as well as
.BI "\-I " dir.
.B \-I
.IR dir .
This syntax is allowed for compatibility with the C
preprocessor's
.B \-I
@ -203,10 +189,10 @@ option, the last one is effective.
If the
.B \-j
option is given without an argument,
.IR make
.BR make
will not limit the number of jobs that can run simultaneously.
.TP 0.5i
.BR \-k , " \-\-keep\-going"
\fB\-k\fR, \fB\-\-keep\-going\fR
Continue as much as possible after an error.
While the target that failed, and those that depend on it, cannot
be remade, the other dependencies of these targets can be processed
@ -219,10 +205,10 @@ others jobs running and the load average is at least
(a floating-point number).
With no argument, removes a previous load limit.
.TP 0.5i
.BR \-L , " \-\-check\-symlink\-times"
\fB\-L\fR, \fB\-\-check\-symlink\-times\fR
Use the latest mtime between symlinks and target.
.TP 0.5i
.BR \-n , " \-\-just\-print" , " \-\-dry\-run" , " \-\-recon"
\fB\-n\fR, \fB\-\-just\-print\fR, \fB\-\-dry\-run\fR, \fB\-\-recon\fR
Print the commands that would be executed, but do not execute them (except in
certain circumstances).
.TP 0.5i
@ -234,7 +220,7 @@ on account of changes in
.IR file .
Essentially the file is treated as very old and its rules are ignored.
.TP 0.5i
.BR \-p , " \-\-print\-data\-base"
\fB\-p\fR, \fB\-\-print\-data\-base\fR
Print the data base (rules and variable values) that results from
reading the makefiles; then execute as usual or as otherwise
specified.
@ -242,63 +228,61 @@ This also prints the version information given by the
.B \-v
switch (see below).
To print the data base without trying to remake any files, use
.B make
.B \-p
.BI \-f /dev/null.
.IR "make \-p \-f/dev/null" .
.TP 0.5i
.BR \-q , " \-\-question"
\fB\-q\fR, \fB\-\-question\fR
``Question mode''.
Do not run any commands, or print anything; just return an exit status
that is zero if the specified targets are already up to date, nonzero
otherwise.
.TP 0.5i
.BR \-r , " \-\-no\-builtin\-rules"
\fB\-r\fR, \fB\-\-no\-builtin\-rules\fR
Eliminate use of the built\-in implicit rules.
Also clear out the default list of suffixes for suffix rules.
.TP 0.5i
.BR \-R , " \-\-no\-builtin\-variables"
\fB\-R\fR, \fB\-\-no\-builtin\-variables\fR
Don't define any built\-in variables.
.TP 0.5i
.BR \-s , " \-\-silent" , " \-\-quiet"
\fB\-s\fR, \fB\-\-silent\fR, \fB\-\-quiet\fR
Silent operation; do not print the commands as they are executed.
.TP 0.5i
.BR \-S , " \-\-no\-keep\-going" , " \-\-stop"
\fB\-S\fR, \fB\-\-no\-keep\-going\fR, \fB\-\-stop\fR
Cancel the effect of the
.B \-k
option.
This is never necessary except in a recursive
.I make
.B make
where
.B \-k
might be inherited from the top-level
.I make
.B make
via MAKEFLAGS or if you set
.B \-k
in MAKEFLAGS in your environment.
.TP 0.5i
.BR \-t , " \-\-touch"
\fB\-t\fR, \fB\-\-touch\fR
Touch files (mark them up to date without really changing them)
instead of running their commands.
This is used to pretend that the commands were done, in order to fool
future invocations of
.IR make .
.BR make .
.TP 0.5i
.B \-\-trace
Print information about the commands invoked by
.IR make.
.BR make.
.TP 0.5i
.BR \-v , " \-\-version"
\fB\-v\fR, \fB\-\-version\fR
Print the version of the
.I make
.B make
program plus a copyright, a list of authors and a notice that there
is no warranty.
.TP 0.5i
.BR \-w , " \-\-print\-directory"
\fB\-w\fR, \fB\-\-print\-directory\fR
Print a message containing the working directory
before and after other processing.
This may be useful for tracking down errors from complicated nests of
recursive
.I make
.B make
commands.
.TP 0.5i
.B \-\-no\-print\-directory
@ -318,25 +302,35 @@ Without
it is almost the same as running a
.I touch
command on the given file before running
.IR make ,
.BR make ,
except that the modification time is changed only in the imagination of
.IR make .
.BR make .
.TP 0.5i
.B \-\-warn\-undefined\-variables
Warn when an undefined variable is referenced.
.SH "EXIT STATUS"
GNU
.I make
.B make
exits with a status of zero if all makefiles were successfully parsed
and no targets that were built failed. A status of one will be returned
if the
.B \-q
flag was used and
.I make
.B make
determines that a target needs to be rebuilt. A status of two will be
returned if any errors were encountered.
.SH "SEE ALSO"
.I "The GNU Make Manual"
The full documentation for
.B make
is maintained as a Texinfo manual. If the
.B info
and
.B make
programs are properly installed at your site, the command
.IP
.B info make
.PP
should give you access to the complete manual.
.SH BUGS
See the chapter `Problems and Bugs' in
.IR "The GNU Make Manual" .
@ -345,9 +339,9 @@ This manual page contributed by Dennis Morse of Stanford University.
Further updates contributed by Mike Frysinger. It has been reworked by Roland
McGrath. Maintained by Paul Smith.
.SH "COPYRIGHT"
Copyright (C) 1992, 1993, 1996, 1999, 2007, 2010 Free Software Foundation, Inc.
This file is part of GNU
.IR make .
Copyright \(co 1992, 1993, 1996, 1999, 2007, 2010 Free Software Foundation, Inc.
This file is part of
.IR "GNU make" .
.LP
GNU Make 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

15
make.h
View File

@ -43,6 +43,12 @@ char *alloca ();
# endif
#endif
/* Disable assert() unless we're a maintainer.
Some asserts are compute-intensive. */
#ifndef MAKE_MAINTAINER_MODE
# define NDEBUG 1
#endif
#ifdef CRAY
/* This must happen before #include <signal.h> so
@ -60,13 +66,12 @@ char *alloca ();
#include <signal.h>
#include <stdio.h>
#include <ctype.h>
#ifdef HAVE_SYS_TIMEB_H
/* SCO 3.2 "devsys 4.2" has a prototype for `ftime' in <time.h> that bombs
unless <sys/timeb.h> has been included first. Does every system have a
<sys/timeb.h>? If any does not, configure should check for it. */
unless <sys/timeb.h> has been included first. */
# include <sys/timeb.h>
#endif
#if TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
@ -456,8 +461,8 @@ void strcache_init (void);
void strcache_print_stats (const char *prefix);
int strcache_iscached (const char *str);
const char *strcache_add (const char *str);
const char *strcache_add_len (const char *str, int len);
int strcache_setbufsize (int size);
const char *strcache_add_len (const char *str, unsigned int len);
int strcache_setbufsize (unsigned int size);
#ifdef HAVE_VFORK_H
# include <vfork.h>

View File

@ -355,11 +355,6 @@ update_file (struct file *file, unsigned int depth)
static void
complain (struct file *file)
{
const char *msg_noparent
= _("%sNo rule to make target `%s'%s");
const char *msg_parent
= _("%sNo rule to make target `%s', needed by `%s'%s");
/* If this file has no_diag set then it means we tried to update it
before in the dontcare mode and failed. The target that actually
failed is not necessarily this file but could be one of its direct
@ -379,6 +374,11 @@ complain (struct file *file)
if (d == 0)
{
const char *msg_noparent
= _("%sNo rule to make target `%s'%s");
const char *msg_parent
= _("%sNo rule to make target `%s', needed by `%s'%s");
/* Didn't find any dependencies to complain about. */
if (!keep_going_flag)
{

View File

@ -16,29 +16,40 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
#include "make.h"
#include <stddef.h>
#include <assert.h>
#include "hash.h"
/* The size (in bytes) of each cache buffer.
Try to pick something that will map well into the heap. */
#define CACHE_BUFFER_SIZE (8192 - 16)
/* A string cached here will never be freed, so we don't need to worry about
reference counting. We just store the string, and then remember it in a
hash so it can be looked up again. */
typedef unsigned short int sc_buflen_t;
struct strcache {
struct strcache *next; /* The next block of strings. */
char *end; /* Pointer to the beginning of the free space. */
int count; /* # of strings in this buffer (for stats). */
int bytesfree; /* The amount of the buffer that is free. */
struct strcache *next; /* The next block of strings. Must be first! */
sc_buflen_t end; /* Offset to the beginning of free space. */
sc_buflen_t bytesfree; /* Free space left in this buffer. */
sc_buflen_t count; /* # of strings in this buffer (for stats). */
char buffer[1]; /* The buffer comes after this. */
};
static int bufsize = CACHE_BUFFER_SIZE;
/* The size (in bytes) of each cache buffer.
Try to pick something that will map well into the heap.
This must be able to be represented by a short int (<=65535). */
#define CACHE_BUFFER_BASE (8192)
#define CACHE_BUFFER_ALLOC(_s) ((_s) - (2 * sizeof (size_t)))
#define CACHE_BUFFER_OFFSET (offsetof (struct strcache, buffer))
#define CACHE_BUFFER_SIZE(_s) (CACHE_BUFFER_ALLOC(_s) - CACHE_BUFFER_OFFSET)
static sc_buflen_t bufsize = CACHE_BUFFER_SIZE (CACHE_BUFFER_BASE);
static struct strcache *strcache = NULL;
static struct strcache *fullcache = NULL;
static unsigned long total_buffers = 0;
static unsigned long total_strings = 0;
static unsigned long total_size = 0;
/* Add a new buffer to the cache. Add it at the front to reduce search time.
This can also increase the overhead, since it's less likely that older
@ -49,50 +60,65 @@ static struct strcache *
new_cache()
{
struct strcache *new;
new = xmalloc (sizeof (*new) + bufsize);
new->end = new->buffer;
new = xmalloc (bufsize + CACHE_BUFFER_OFFSET);
new->end = 0;
new->count = 0;
new->bytesfree = bufsize;
new->next = strcache;
strcache = new;
++total_buffers;
return new;
}
static const char *
add_string(const char *str, int len)
add_string (const char *str, unsigned int len)
{
struct strcache *best = NULL;
char *res;
struct strcache *sp;
const char *res;
struct strcache **spp = &strcache;
/* We need space for the nul char. */
unsigned int sz = len + 1;
/* If the string we want is too large to fit into a single buffer, then
we're screwed; nothing will ever fit! Change the maximum size of the
cache to be big enough. */
if (len > bufsize)
bufsize = len * 2;
/* First, find a cache with enough free space. We always look through all
the blocks and choose the one with the best fit (the one that leaves the
least amount of space free). */
for (sp = strcache; sp != NULL; sp = sp->next)
if (sp->bytesfree > len && (!best || best->bytesfree > sp->bytesfree))
best = sp;
no existing cache is large enough. Change the maximum size. */
if (sz > bufsize)
bufsize = CACHE_BUFFER_SIZE ((((sz + 1) / CACHE_BUFFER_BASE) + 1)
* CACHE_BUFFER_BASE);
else
/* Find the first cache with enough free space. */
for (; *spp != NULL; spp = &(*spp)->next)
if ((*spp)->bytesfree > sz)
break;
/* If nothing is big enough, make a new cache. */
if (!best)
best = new_cache();
sp = *spp;
if (sp == NULL)
{
sp = new_cache ();
spp = &sp;
}
assert (best->bytesfree > len);
/* Add the string to this cache. */
res = &sp->buffer[sp->end];
memmove (res, str, len);
res[len] = '\0';
sp->end += sz;
sp->bytesfree -= sz;
++sp->count;
/* Add the string to the best cache. */
res = best->end;
memcpy (best->end, str, len);
best->end += len;
*(best->end++) = '\0';
best->bytesfree -= len + 1;
++best->count;
/* If the amount free in this cache is less than the average string size,
consider it full and move it to the full list. */
++total_strings;
total_size += sz;
if (sp->bytesfree < (total_size / total_strings) + 1)
{
*spp = (*spp)->next;
sp->next = fullcache;
fullcache = sp;
}
return res;
}
@ -128,7 +154,7 @@ add_hash (const char *str, int len)
char *const *slot = (char *const *) hash_find_slot (&strings, str);
const char *key = *slot;
/* Count the total number of adds we performed. */
/* Count the total number of add operations we performed. */
++total_adds;
if (!HASH_VACANT (key))
@ -147,7 +173,10 @@ strcache_iscached (const char *str)
struct strcache *sp;
for (sp = strcache; sp != 0; sp = sp->next)
if (str >= sp->buffer && str < sp->end)
if (str >= sp->buffer && str < sp->buffer + sp->end)
return 1;
for (sp = fullcache; sp != 0; sp = sp->next)
if (str >= sp->buffer && str < sp->buffer + sp->end)
return 1;
return 0;
@ -163,7 +192,7 @@ strcache_add (const char *str)
}
const char *
strcache_add_len (const char *str, int len)
strcache_add_len (const char *str, unsigned int len)
{
/* If we're not given a nul-terminated string we have to create one, because
the hashing functions expect it. */
@ -179,7 +208,7 @@ strcache_add_len (const char *str, int len)
}
int
strcache_setbufsize(int size)
strcache_setbufsize(unsigned int size)
{
if (size > bufsize)
bufsize = size;
@ -198,49 +227,65 @@ strcache_init (void)
void
strcache_print_stats (const char *prefix)
{
int numbuffs = 0, numstrs = 0;
int totsize = 0, avgsize, maxsize = 0, minsize = bufsize;
int totfree = 0, avgfree, maxfree = 0, minfree = bufsize;
int lastused = 0, lastfree = 0;
const struct strcache *sp;
unsigned long numbuffs = 0, fullbuffs = 0;
unsigned long totfree = 0, maxfree = 0, minfree = bufsize;
if (strcache)
if (! strcache)
{
const struct strcache *sp;
/* Count the first buffer separately since it's not full. */
lastused = strcache->end - strcache->buffer;
lastfree = strcache->bytesfree;
for (sp = strcache->next; sp != NULL; sp = sp->next)
{
int bf = sp->bytesfree;
int sz = sp->end - sp->buffer;
++numbuffs;
numstrs += sp->count;
totsize += sz;
maxsize = (sz > maxsize ? sz : maxsize);
minsize = (sz < minsize ? sz : minsize);
totfree += bf;
maxfree = (bf > maxfree ? bf : maxfree);
minfree = (bf < minfree ? bf : minfree);
}
printf(_("\n%s No strcache buffers\n"), prefix);
return;
}
avgsize = numbuffs ? (int)(totsize / numbuffs) : 0;
avgfree = numbuffs ? (int)(totfree / numbuffs) : 0;
/* Count the first buffer separately since it's not full. */
for (sp = strcache->next; sp != NULL; sp = sp->next)
{
sc_buflen_t bf = sp->bytesfree;
printf (_("\n%s # of strings in strcache: %d / lookups = %lu / hits = %lu\n"),
prefix, numstrs, total_adds, (total_adds - numstrs));
printf (_("%s # of strcache buffers: %d (* %d B/buffer = %d B)\n"),
prefix, (numbuffs + 1), bufsize, ((numbuffs + 1) * bufsize));
printf (_("%s strcache used: total = %d (%d) / max = %d / min = %d / avg = %d\n"),
prefix, totsize, lastused, maxsize, minsize, avgsize);
printf (_("%s strcache free: total = %d (%d) / max = %d / min = %d / avg = %d\n"),
prefix, totfree, lastfree, maxfree, minfree, avgfree);
totfree += bf;
maxfree = (bf > maxfree ? bf : maxfree);
minfree = (bf < minfree ? bf : minfree);
fputs (_("\n# strcache hash-table stats:\n# "), stdout);
++numbuffs;
}
for (sp = fullcache; sp != NULL; sp = sp->next)
{
sc_buflen_t bf = sp->bytesfree;
totfree += bf;
maxfree = (bf > maxfree ? bf : maxfree);
minfree = (bf < minfree ? bf : minfree);
++numbuffs;
++fullbuffs;
}
/* Make sure we didn't lose any buffers. */
assert (total_buffers == numbuffs + 1);
printf (_("\n%s strcache buffers: %lu (%lu) / strings = %lu / storage = %lu B / avg = %lu B\n"),
prefix, numbuffs + 1, fullbuffs, total_strings, total_size,
(total_size / total_strings));
printf (_("%s current buf: size = %hu B / used = %hu B / count = %hu / avg = %hu B\n"),
prefix, bufsize, strcache->end, strcache->count,
(strcache->end / strcache->count));
if (numbuffs)
{
unsigned long sz = total_size - bufsize;
unsigned long cnt = total_strings - strcache->count;
sc_buflen_t avgfree = totfree / numbuffs;
printf (_("%s other used: total = %lu B / count = %lu / avg = %lu B\n"),
prefix, sz, cnt, sz / cnt);
printf (_("%s other free: total = %lu B / max = %lu B / min = %lu B / avg = %hu B\n"),
prefix, totfree, maxfree, minfree, avgfree);
}
printf (_("\n%s strcache performance: lookups = %lu / hit rate = %lu%%\n"),
prefix, total_adds, (long unsigned)(100.0 * (total_adds - total_strings) / total_adds));
fputs (_("# hash-table stats:\n# "), stdout);
hash_print_stats (&strings, stdout);
}