#!/usr/bin/perl #---------------------------------------------------------------------- # # Generate wait events support files from wait_event_names.txt: # - wait_event_types.h (if --code is passed) # - pgstat_wait_event.c (if --code is passed) # - wait_event_funcs_data.c (if --code is passed) # - wait_event_types.sgml (if --docs is passed) # # Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/backend/utils/activity/generate-wait_event_types.pl # #---------------------------------------------------------------------- use strict; use warnings FATAL => 'all'; use Getopt::Long; my $output_path = '.'; my $gen_docs = 0; my $gen_code = 0; my $continue = "\n"; my %hashwe; GetOptions( 'outdir:s' => \$output_path, 'docs' => \$gen_docs, 'code' => \$gen_code) || usage(); die "Needs to specify --docs or --code" if (!$gen_docs && !$gen_code); die "Not possible to specify --docs and --code simultaneously" if ($gen_docs && $gen_code); open my $wait_event_names, '<', $ARGV[0] or die; my @lines; my $section_name; my $note; my $note_name; # Remove comments and empty lines and add waitclassname based on the section while (<$wait_event_names>) { chomp; # Skip comments next if /^#/; # Skip empty lines next if /^\s*$/; # Get waitclassname based on the section if (/^Section: ClassName(.*)/) { $section_name = $_; $section_name =~ s/^.*- //; next; } push(@lines, $section_name . "\t" . $_); } # Sort the lines based on the second column. # uc() is being used to force the comparison to be case-insensitive. my @lines_sorted = sort { uc((split(/\t/, $a))[1]) cmp uc((split(/\t/, $b))[1]) } @lines; # Read the sorted lines and populate the hash table foreach my $line (@lines_sorted) { die "unable to parse wait_event_names.txt for line $line\n" unless $line =~ /^(\w+)\t+(\w+)\t+("\w.*\.")$/; (my $waitclassname, my $waiteventname, my $waitevendocsentence) = split(/\t/, $line); # Generate the element name for the enums based on the # description. The C symbols are prefixed with "WAIT_EVENT_". my $waiteventenumname = "WAIT_EVENT_$waiteventname"; # Build the descriptions. These are in camel-case. # LWLock and Lock classes do not need any modifications. my $waiteventdescription = ''; if ( $waitclassname eq 'WaitEventLWLock' || $waitclassname eq 'WaitEventLock') { $waiteventdescription = $waiteventname; } else { my @waiteventparts = split("_", $waiteventname); foreach my $waiteventpart (@waiteventparts) { $waiteventdescription .= substr($waiteventpart, 0, 1) . lc(substr($waiteventpart, 1, length($waiteventpart))); } } # Store the event into the list for each class. my @waiteventlist = [ $waiteventenumname, $waiteventdescription, $waitevendocsentence ]; push(@{ $hashwe{$waitclassname} }, @waiteventlist); } # Generate the .c and .h files. if ($gen_code) { # Include PID in suffix in case parallel make runs this script # multiple times. my $htmp = "$output_path/wait_event_types.h.tmp$$"; my $ctmp = "$output_path/pgstat_wait_event.c.tmp$$"; my $wctmp = "$output_path/wait_event_funcs_data.c.tmp$$"; open my $h, '>', $htmp or die "Could not open $htmp: $!"; open my $c, '>', $ctmp or die "Could not open $ctmp: $!"; open my $wc, '>', $wctmp or die "Could not open $wctmp: $!"; my $header_comment = '/*------------------------------------------------------------------------- * * %s * Generated wait events infrastructure code * * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * NOTES * ****************************** * *** DO NOT EDIT THIS FILE! *** * ****************************** * * It has been GENERATED by src/backend/utils/activity/generate-wait_event_types.pl * *------------------------------------------------------------------------- */ '; printf $h $header_comment, 'wait_event_types.h'; printf $h "#ifndef WAIT_EVENT_TYPES_H\n"; printf $h "#define WAIT_EVENT_TYPES_H\n\n"; printf $h "#include \"utils/wait_event.h\"\n\n"; printf $c $header_comment, 'pgstat_wait_event.c'; printf $wc $header_comment, 'wait_event_funcs_data.c'; # Generate the pgstat_wait_event.c and wait_event_types.h files # uc() is being used to force the comparison to be case-insensitive. foreach my $waitclass (sort { uc($a) cmp uc($b) } keys %hashwe) { # Don't generate the pgstat_wait_event.c and wait_event_types.h files # for Extension, LWLock and Lock, these are handled independently. next if ( $waitclass eq 'WaitEventExtension' || $waitclass eq 'WaitEventLWLock' || $waitclass eq 'WaitEventLock'); my $last = $waitclass; $last =~ s/^WaitEvent//; my $lastuc = uc $last; my $lastlc = lc $last; my $firstpass = 1; my $pg_wait_class; printf $c "static const char *\npgstat_get_wait_$lastlc($waitclass w)\n{\n"; printf $c "\tconst char *event_name = \"unknown wait event\";\n\n"; printf $c "\tswitch (w)\n\t{\n"; foreach my $wev (@{ $hashwe{$waitclass} }) { if ($firstpass) { printf $h "typedef enum\n{\n"; $pg_wait_class = "PG_WAIT_" . $lastuc; printf $h "\t%s = %s", $wev->[0], $pg_wait_class; $continue = ",\n"; } else { printf $h "%s\t%s", $continue, $wev->[0]; $continue = ",\n"; } $firstpass = 0; printf $c "\t\t case %s:\n", $wev->[0]; # Apply quotes to the wait event name string. printf $c "\t\t\t event_name = \"%s\";\n\t\t\t break;\n", $wev->[1]; } printf $h "\n} $waitclass;\n\n"; printf $c "\t\t\t /* no default case, so that compiler will warn */\n"; printf $c "\t}\n\n"; printf $c "\treturn event_name;\n"; printf $c "}\n\n"; } # Generate wait_event_funcs_data.c, building the contents of a static # C structure holding all the information about the wait events. # uc() is being used to force the comparison to be case-insensitive, # even though it is not required here. foreach my $waitclass (sort { uc($a) cmp uc($b) } keys %hashwe) { my $last = $waitclass; $last =~ s/^WaitEvent//; foreach my $wev (@{ $hashwe{$waitclass} }) { my $new_desc = substr $wev->[2], 1, -2; # Escape single quotes. $new_desc =~ s/'/\\'/g; # Replace the "quote" markups by real ones. $new_desc =~ s/(.*?)<\/quote>/\\"$1\\"/g; # Remove SGML markups. $new_desc =~ s/<.*?>(.*?)<.*?>/$1/g; # Tweak contents about links # on GUCs, while (my ($capture) = $new_desc =~ m//g) { $capture =~ s/-/_/g; $new_desc =~ s//$capture/g; } # Then remove any reference to # "see ". $new_desc =~ s/; see.*$//; # Build one element of the C structure holding the # wait event info, as of (type, name, description). printf $wc "\t{\"%s\", \"%s\", \"%s\"},\n", $last, $wev->[1], $new_desc; } } printf $h "#endif /* WAIT_EVENT_TYPES_H */\n"; close $h; close $c; close $wc; rename($htmp, "$output_path/wait_event_types.h") || die "rename: $htmp to $output_path/wait_event_types.h: $!"; rename($ctmp, "$output_path/pgstat_wait_event.c") || die "rename: $ctmp to $output_path/pgstat_wait_event.c: $!"; rename($wctmp, "$output_path/wait_event_funcs_data.c") || die "rename: $wctmp to $output_path/wait_event_funcs_data.c: $!"; } # Generate the .sgml file. elsif ($gen_docs) { # Include PID in suffix in case parallel make runs this multiple times. my $stmp = "$output_path/wait_event_names.s.tmp$$"; open my $s, '>', $stmp or die "Could not open $stmp: $!"; # uc() is being used to force the comparison to be case-insensitive. foreach my $waitclass (sort { uc($a) cmp uc($b) } keys %hashwe) { my $last = $waitclass; $last =~ s/^WaitEvent//; my $lastlc = lc $last; printf $s " \n", $lastlc; printf $s " Wait Events of Type <literal>%s</literal>\n", ucfirst($lastlc); printf $s " \n"; printf $s " \n"; printf $s " \n"; printf $s " $last Wait Event\n"; printf $s " Description\n"; printf $s " \n"; printf $s " \n\n"; printf $s " \n"; foreach my $wev (@{ $hashwe{$waitclass} }) { printf $s " \n"; printf $s " %s\n", $wev->[1]; printf $s " %s\n", substr $wev->[2], 1, -1; printf $s " \n"; } printf $s " \n"; printf $s " \n"; printf $s "
\n\n"; } close $s; rename($stmp, "$output_path/wait_event_types.sgml") || die "rename: $stmp to $output_path/wait_event_types.sgml: $!"; } close $wait_event_names; sub usage { die <] [--code ] [ --sgml ] input_file Options: --outdir Output directory (default '.') --code Generate C and header files. --sgml Generate wait_event_types.sgml. generate-wait_event_types.pl generates the SGML documentation and code related to wait events. This should use wait_event_names.txt in input, or an input file with a compatible format. Report bugs to . EOM }