mp4-sa-> the mp4-sa book-> special topics->debugging |
Sections
|
Language Elements:printf   |
IntroductionA popular staple of afternoon television is the cooking show. At the start of the show, a complex meal is planned, and by the end of the show, a perfect dinner pops out of the kitchen. The examples shown in this book have a similar flavor. Code is shown on the right-hand panel, which always works to produce the desired audio output. Like TV cooking shows, the book examples don't show the real development process: syntax errors, compiler bugs, program crashes, and bad-sounding audio. In this chapter, we describe common ways that SAOL programs fail to work, and techniques to use to find and fix the problems. The right panel shows a list of the major traps in the development cycle. In the sections of this chapter, we describe how to approach these problems. In this chapter, we use the sfront SAOL-to-C translator, running under Linux, to demonstrate debugging. However, even if you use another SAOL development systems, the concepts in this chapter should help you debug your programs. |
Errors: Where, When, and What
Before execution:
During execution:
After execution:
|
Reported ErrorsMany SAOL programming errors are detected automatically and reported to the user. Depending on the error, sfront may report a compile-time error, or the C program sfront creates may terminate and report an error. The right panel shows one kind of sfront compile-time error, a syntax error (in this case, a missing semicolon). Since sfront can't understand the SAOL program without the semicolon, its error message doesn't describe the problem exactly. However, it does report a line number and filename, which (usually) is sufficient to debug the problem. |
Syntax Error ReportSAOL fragment: instr tremelo ( ) { asig count // lacks ';' ksig kinit; sfront reports: Syntax error during -saolfile parsing. Error occurred near line 28 in file min.saol: instr tremelo ( ) { asig count ksig kinit; ksig halfperiod; Ending sfront. |
A second type of compile-time error is a type mismatch error. The right panel shows an example of a type mismatch (a table used in a signal expression). Because sfront successfully understood the syntax of the program, it was able to print a meaningful error message. Whenever you run sfront, your session should end in one of the following ways:
However, if your session ends in one of the following ways:
|
Type Error ReportSAOL fragment: instr square ( ) { table delta(harm, 128, 1); delta = delta + 1; // type error sfront reports: Error: Table(map) delta used inappropriately. Error occured near line 56 in file min.saol: table delta(harm, 128, 1); delta = delta + 1; Ending sfront. |
When sfront creates a C program, it includes error checking code for certain types of errors. If this error checking code is tripped, a run-time error report is printed and the program exits. The right panel shows an example of run-time error checking. In this case, a table is defined, using the sample wavetable generator. However, the file specified doesn't actually exist. During execution, the program tries to open the file and fails; it then prints the run-time error shown and exits. Reported errors are the simplest type of run-time error to catch and fix. To help the programmer write good code, the MP4-SA standard mandates that decoders catch report many kinds of real-time errors checks. Eventually, sfront will implement all of these error checks. At the present time, however, sfront implements many but not all required checks. Specifically, sfront does not check to see if the index value of an array, oparray, or tablemap is out of range. In addition, CPU intensive checks on certain core opcodes, such as checking the range of the index parameter to tableread and tablewrite, are only performed if sfront is run with the -isocheck flag. If your program does one of these illegal operations, it won't produce a run-time error message. Instead, the program might crash, or it may run forever, or (most likely) the sound created might not be what it should. |
Runtime Error ReportSAOL fragment: // file doesn't actually exist global { table oneclap(sample, -1, "samp_2.aif"); Execution trace: gcc -O3 sa.c -lm -o sa ./sa Runtime Error. Location: File claps.saol near line 10. While executing: table. Potential problem: Samplefile not found (aif(f)). Exiting program. |
Program CrashesIn many ways, a program that crashes is easier to debug than one that silently does the wrong thing.In the future, sfront will include modes for reporting exactly where and how a program crashes. For now, the easiest way to debug a program crash under Linux is to follow these steps:
It may be helpful to look at the sa.c file in this process, if you are comfortable with the C language. The remainder of this chapter focuses on techniques for handling SAOL programs that don't crash, but which produce the wrong audio. |
Running Gdb[1] Run sfront without -except option [2] Compile sa.c with debug switch: gcc -g -O3 sa.c -lm -o sa [3] Run gdb: gdb ./sa GNU gdb 4.17.0.11 (gdb) run Starting program: ./sa Segmentation fault, in arpsound2__sym_butter_gainlp3 (gdb) bt #0 in arpsound2__sym_butter_gainlp3 () #1 in arpsound2_kpass () #2 in main_kpass () #3 in main () [3] Example what gdb prints in response to "bt" as shown above. In this case, bug was in the kpass of instr arpsound2, during a call to opcode butter_gainlp3. |
Finding Runtime ErrorsFinding the root cause of a run-time problem in a SAOL program may be a difficult task. Rate semantics may make even simple programs difficult to understand. Ancillary factors such as a complex SASL or MIDI track, real-time control, or audio input can make matters even worse. The first step in debugging a complex SAOL program is to simplify the program itself. Store a safety copy of the original program, and then try the following techniques to simplify the problem:
The techniques can be useful in tracking down a problem to a section of SAOL code. Once the problem area is localized, a careful examination of the source code may reveal the error. Other times, the only way to find the root cause of the problem is to print out variables over time and watch them evolve, as we describe in the next section. |
|
printfSAOL programs compiled under sfront can use the printf statement, described on the right panel, to print out SAOL scalar program variables. Note that printf is an sfront extension of SAOL, and is not part of the standard language. The SAOL printf statement borrows its basic syntax from the ANSI C standard library function printf. The first argument is a format string, that contains the text to be printed out. When printed, the first instance of %f is replaced with the value of the second printf argument, the second instance of %f is replaced with the value of the third argument, ect. The SAOL printf statement differs from the C printf function in several ways:
For simplicity, the right-panel description of printf format strings only show plain %f (for variables) and %s (for strings) directives. Since SAOL printf statements are implemented in the sa.c file as C printf functions, experienced C programs are free to use more complex format directives for floating-point numbers.
Printf statements write to stdout, while
all error diagnostics will write to stderr.
Printf works this way so that stdout may
be redirected to a file or program, while
error messages are still printed to the screen.
The first shell command below redirects printf
output to the file log, the second
redirects prints to the text viewer more:
Its a good idea to use the sfront option -except when redirecting to a log file, so that a program crash does not delete the log file. The most powerful part of the SAOL printf statement is its rate semantics. By careful choice of arguments, printing will occur at the i-rate, k-rate, or a-rate. In the following sections, we describe useful printf techniques at each rate. |
Statement syntaxprintf("fmt" [, arg1, arg2, ..]); Where: "fmt": is a (required) quoted string. it may contain directives beginning with the % character. Most users will only need the %f character (for printing expressions) and the %s character (for printing quoted strings). Use the \n characters for carriage return, the \t character for tab. Replace %f with %e to print using scientific notation, or %g to adaptively choose normal or scientific notation. argk: are optional arguments. each must be a scalar signal expression or a quoted string. arg1's value is printed in place of the first %f or %s, arg2's value is printed in place of the second %f or %s, ect. expressions must match with %f's, and strings with %s. Note that printf is a statement, not an opcode. The rate of the expression is the rate of the fastest arguments, with strings considered i-rate. Expressions may be special-ops, in which case the printf is a special-op. Example: instr foo(i) { ksig k; asig a; i = 12; k = 5; a = 6; printf("hello world\n"); printf("%s%f\n","start of instr",i); printf("krate %f %f\n",i, k); printf("arate %f\n",a); } Prints out (from instantiation): hello world start of instr 12.000000 krate 12.000000 5.000000 arate 6.000000 arate 6.000000 [...] arate 6.000000 arate 6.000000 krate 12.000000 5.000000 arate 6.000000 arate 6.000000 [...] [...] |
I-rate DebuggingI-rate printf statements run when instrument instances are created. In many cases, the underlying source of an a-rate or k-rate bug can be understood by examining values at the i-rate. Useful items to print include
Sometimes, bugs happen in the initialization process of the SAOL program, at time zero. To track these problems down, try adding i-rate printf statements in effects instruments, the startup instrument, and in user-defined opcodes called in the global block. |
Useful ivar standard namesivar time The time that the instance was created. ivar dur The duration of the instance, or -1 if no duration. ivar inchan For effects instances: the number of input audio channels provided. ivar outchan The number of audio output channels for the instrument. ivar channel For MIDI instruments: the extended channel number for the instance. ivar preset For MIDI instruments: the preset number for this instance. |
K-rate DebuggingIf i-rate printf statements do not find a bug, it may be necessary to print out k-rate variable values. A key problem with k-rate printf statements is the large amount of data produced. Since an unguarded k-rate printf generates data once per k-cucle, it may produce hundreds of lines of text per second. To solve this problem, only use k-rate printf statements inside of if statements, whose guard values are chosen to be rarely true. Common guard techniques include:
An alternative approach is to print information on every k-cycle, and to direct this information to a file for examination with a text editor. |
Useful ksig standard namesksig itime The elapsed time since the instance was created. ksig released Normally 0, but 1 if the instance is scheduled for termination at the end of the current execution cycle. ksig MIDIctrl[128] ksig MIDIbend ksig MIDItouch For MIDI instances, monitors MIDI data from the channel that created it. For non-MIDI instances in a SAOL program controlled by MIDI, monitors the MIDI master channel (usually channel 0). imports exports ksig params[128] Communicates with the control driver in an application- specific way; good for debug of new control drivers. |
A-rate DebuggingThe most difficult debugging sessions involve monitoring a-rate changes. In most cases, unguarded printf statements are not practical, since a short sound may produce one-hundred thousand lines of text! As in k-rate debugging, enclosing all printf statements with if statements whose guards rarely execute is the key to successful debugging. Since a-rate problems often involve clicks or run-away waveforms, guard expressions often are tuned to look for these waveform characteristics. Another technique involves the use of specialops, such as the rms opcode. This opcode examines its parameter at the a-rate, and returns the root-mean-square value of the waveform at the k-rate. A printf statement with a specialop expression prints out text at the k-rate. |
|
Next: Part V/2: Templates |
|
mp4-sa-> the mp4-sa book-> special topics->debugging |