Go back to previous page
Go back to home page
Last update:
16-May-2010
Author: R. Koucha
How to use printf() efficiently
Introduction
In lots of software, I can see the following in red
color (one example among numerous ones !):
BRCode_t ethsw_run_print_bist(int switch_ID)
{
ethsw_bist_t bist_result;
BRCode_t rt;
char * sw_name;
if (!KETHSW_VALID_SWITCH_ID(switch_ID))
{
printf("Invalid switch ID (%d)\n", switch_ID);
return BRC_ERR;
}
rt = ethsw_bist_run(switch_ID, &bist_result);
printf("BIST result:\n");
switch (bist_result.device_ID)
{
case ZL_ZL33032_ID:
sw_name =
ETHSW_NAME1;
break;
case ZL_ZL33036_ID:
sw_name =
ETHSW_NAME3;
break;
case ZL_ZL33050_ID:
sw_name =
ETHSW_NAME2;
break;
default:
sw_name = "Unknown
switch !";
break;
}
printf(" Device
ID : %s (0x%x)\n",
sw_name,bist_result.device_ID);
printf(" Device revision: %d\n",
bist_result.device_revision);
printf(" RAM status :
%s\n", (bist_result.RAM_OK )?"OK"
:"KO");
printf(" BIST result :
%s\n", (rt ==
BRC_OK
)?"OK"
:"KO");
printf("\n!! Warning: Switch has been stopped and restarted to
run
BIST !!\n");
return rt;
}
This is bad for the following reasons :
1. This is not efficient
Why are we calling printf() several times since only one call
would be sufficient. We would save some CPU time.
2. The displays may be mixed
As the data are displayed in multiple shots (one shot per printf()
call), the calling task may be preempted between the calls by another
task which may call printf() as well. So, this would trigger
the mix of displays coming from multiple tasks. This does not
facilitate the reading of the traces while debugging !
3. The memory footprint is more important
The multiple calls to printf() triggers the generation of
multiple identical sets of instructions: one set per printf()
call. This makes the generated code fat.
Proposed better code
Here is the function fixed to avoid trace mixing, save memory space
(the assembly code shows that we save 92
bytes of instructions on a PowerPC architecture) and
save some CPU time...
BRCode_t ethsw_run_print_bist(int switch_ID)
{
ethsw_bist_t bist_result;
BRCode_t rt;
char * sw_name;
if (!KETHSW_VALID_SWITCH_ID(switch_ID))
{
printf("Invalid switch ID (%d)\n", switch_ID);
return BRC_ERR;
}
rt = ethsw_bist_run(switch_ID, &bist_result);
switch (bist_result.device_ID)
{
case ZL_ZL33032_ID:
sw_name =
ETHSW_NAME1;
break;
case ZL_ZL33036_ID:
sw_name =
ETHSW_NAME3;
break;
case ZL_ZL33050_ID:
sw_name =
ETHSW_NAME2;
break;
default:
sw_name = "Unknown
switch !";
break;
}
printf("BIST result:\n"
"
Device ID : %s (0x%x)\n"
"
Device revision: %d\n"
"
RAM status : %s\n"
"
BIST result : %s\n"
"\n!! Warning: Switch
has been stopped and restarted to run
BIST !!\n"
,
sw_name,bist_result.device_ID,
bist_result.device_revision,
(bist_result.RAM_OK)?"OK" :"KO",
(rt == BRC_OK)?"OK"
:"KO"
);
return rt;
}
Conclusion
The preceding applies to all the printf()
family routines... Note that
some functions may be limited to 4KB of displayed data in one shot.
Of course, this is not a revolution. We will not definitely solve the
memory space and performance problems that we may face but it is so
simple to do that it is worth it !
Some interesting links
About the
author
The author is an engineer in computer sciences located in France. He
can be contacted here or
you can have
a look at his WEB
home page.