• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * @file ophelp.c
3  * Print out PMC event information
4  *
5  * @remark Copyright 2002 OProfile authors
6  * @remark Read the file COPYING
7  *
8  * @author John Levon
9  * @author Philippe Elie
10  */
11 
12 #define _GNU_SOURCE
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <limits.h>
17 
18 #include "op_version.h"
19 #include "op_events.h"
20 #include "op_popt.h"
21 #include "op_cpufreq.h"
22 #include "op_hw_config.h"
23 #include "op_string.h"
24 #include "op_alloc_counter.h"
25 #include "op_parse_event.h"
26 #include "op_libiberty.h"
27 #include "op_xml_events.h"
28 
29 static char const ** chosen_events;
30 static int num_chosen_events;
31 struct parsed_event * parsed_events;
32 static op_cpu cpu_type = CPU_NO_GOOD;
33 static char * cpu_string;
34 static int callgraph_depth;
35 static int want_xml;
36 
37 static poptContext optcon;
38 
39 
40 /// return the Hamming weight (number of set bits)
hweight(size_t mask)41 static size_t hweight(size_t mask)
42 {
43 	size_t count = 0;
44 
45 	while (mask) {
46 		mask &= mask - 1;
47 		count++;
48 	}
49 
50 	return count;
51 }
52 
do_arch_specific_event_help(struct op_event * event)53 static void do_arch_specific_event_help(struct op_event * event)
54 {
55 	switch (cpu_type) {
56 	case CPU_PPC64_CELL:
57 		printf("Group %u :", event->val / 100);
58 		break;
59 	default:
60 		break;
61 	}
62 }
63 
64 #define LINE_LEN 99
65 
word_wrap(int indent,int * column,char * msg)66 static void word_wrap(int indent, int *column, char *msg)
67 {
68 	while (*msg) {
69 		int wlen = strcspn(msg, " ");
70 		if (*column + wlen > LINE_LEN) {
71 			printf("\n%*s", indent, "");
72 			*column = indent;
73 		}
74 		printf("%.*s ", wlen, msg);
75 		*column += wlen + 1;
76 		msg += wlen;
77 		msg += strspn(msg, " ");
78 	}
79 }
80 
81 /**
82  * help_for_event - output event name and description
83  * @param i  event number
84  *
85  * output an help string for the event @i
86  */
help_for_event(struct op_event * event)87 static void help_for_event(struct op_event * event)
88 {
89 	int column;
90 	uint i, j;
91 	uint mask;
92 	size_t nr_counters;
93 	char buf[32];
94 
95 	do_arch_specific_event_help(event);
96 	nr_counters = op_get_nr_counters(cpu_type);
97 
98 	/* Sanity check */
99 	if (!event)
100 		return;
101 
102 	printf("%s", event->name);
103 
104 	if(event->counter_mask != 0) {
105 		printf(": (counter: ");
106 
107 		mask = event->counter_mask;
108 		if (hweight(mask) == nr_counters) {
109 			printf("all");
110 		} else {
111 			for (i = 0; i < CHAR_BIT * sizeof(event->counter_mask); ++i) {
112 				if (mask & (1 << i)) {
113 					printf("%d", i);
114 					mask &= ~(1 << i);
115 					if (mask)
116 						printf(", ");
117 				}
118 			}
119 		}
120 	} else	if (event->ext != NULL) {
121 		/* Handling extended feature interface */
122 		printf(": (ext: %s", event->ext);
123 	} else {
124 		/* Handling arch_perfmon case */
125 		printf(": (counter: all");
126 	}
127 
128 	printf(")\n\t");
129 	column = 8;
130 	word_wrap(8, &column, event->desc);
131 	snprintf(buf, sizeof buf, "(min count: %d)", event->min_count);
132 	word_wrap(8, &column, buf);
133 	putchar('\n');
134 
135 	if (strcmp(event->unit->name, "zero")) {
136 
137 		printf("\tUnit masks (default 0x%x)\n",
138 		       event->unit->default_mask);
139 		printf("\t----------\n");
140 
141 		for (j = 0; j < event->unit->num; j++) {
142 			printf("\t0x%.2x: ",
143 			       event->unit->um[j].value);
144 			column = 14;
145 			word_wrap(14, &column, event->unit->um[j].desc);
146 			putchar('\n');
147 		}
148 	}
149 }
150 
151 
check_event(struct parsed_event * pev,struct op_event const * event)152 static void check_event(struct parsed_event * pev,
153 			struct op_event const * event)
154 {
155 	int ret;
156 	int min_count;
157 	int const callgraph_min_count_scale = 15;
158 
159 	if (!event) {
160 		event = find_event_by_name(pev->name, 0, 0);
161 		if (event)
162 			fprintf(stderr, "Invalid unit mask %x for event %s\n",
163 				pev->unit_mask, pev->name);
164 		else
165 			fprintf(stderr, "No event named %s is available.\n",
166 				pev->name);
167 		exit(EXIT_FAILURE);
168 	}
169 
170 	ret = op_check_events(0, event->val, pev->unit_mask, cpu_type);
171 
172 	if (ret & OP_INVALID_UM) {
173 		fprintf(stderr, "Invalid unit mask 0x%x for event %s\n",
174 		        pev->unit_mask, pev->name);
175 		exit(EXIT_FAILURE);
176 	}
177 
178 	min_count = event->min_count;
179 	if (callgraph_depth)
180 		min_count *= callgraph_min_count_scale;
181 	if (pev->count < min_count) {
182 		fprintf(stderr, "Count %d for event %s is below the "
183 		        "minimum %d\n", pev->count, pev->name, min_count);
184 		exit(EXIT_FAILURE);
185 	}
186 }
187 
188 
resolve_events(void)189 static void resolve_events(void)
190 {
191 	size_t count, count_events;
192 	size_t i, j;
193 	size_t * counter_map;
194 	size_t nr_counters = op_get_nr_counters(cpu_type);
195 	struct op_event const * selected_events[num_chosen_events];
196 
197 	count = parse_events(parsed_events, num_chosen_events, chosen_events);
198 
199 	for (i = 0; i < count; ++i) {
200 		for (j = i + 1; j < count; ++j) {
201 			struct parsed_event * pev1 = &parsed_events[i];
202 			struct parsed_event * pev2 = &parsed_events[j];
203 
204 			if (!strcmp(pev1->name, pev2->name) &&
205 			    pev1->count == pev2->count &&
206 			    pev1->unit_mask == pev2->unit_mask &&
207 			    pev1->kernel == pev2->kernel &&
208 			    pev1->user == pev2->user) {
209 				fprintf(stderr, "All events must be distinct.\n");
210 				exit(EXIT_FAILURE);
211 			}
212 		}
213 	}
214 
215 	for (i = 0, count_events = 0; i < count; ++i) {
216 		struct parsed_event * pev = &parsed_events[i];
217 
218 		/* For 0 unit mask always do wild card match */
219 		selected_events[i] = find_event_by_name(pev->name, pev->unit_mask,
220 					pev->unit_mask ? pev->unit_mask_valid : 0);
221 		check_event(pev, selected_events[i]);
222 
223 		if (selected_events[i]->ext == NULL) {
224 			count_events++;
225 		}
226 	}
227 	if (count_events > nr_counters) {
228 		fprintf(stderr, "Not enough hardware counters. "
229 				"Need %lu counters but only has %lu.\n",
230 				(unsigned long) count_events,
231 				(unsigned long) nr_counters);
232 		exit(EXIT_FAILURE);
233 	}
234 
235 	counter_map = map_event_to_counter(selected_events, count, cpu_type);
236 
237 	if (!counter_map) {
238 		fprintf(stderr, "Couldn't allocate hardware counters for the selected events.\n");
239 		exit(EXIT_FAILURE);
240 	}
241 
242 	for (i = 0; i < count; ++i)
243 		if(counter_map[i] == (size_t)-1)
244 			if (selected_events[i]->ext != NULL)
245 				printf("%s ", (char*) selected_events[i]->ext);
246 			else
247 				printf("N/A ");
248 		else
249 			printf("%d ", (unsigned int) counter_map[i]);
250 	printf("\n");
251 
252 	free(counter_map);
253 }
254 
255 
show_unit_mask(void)256 static void show_unit_mask(void)
257 {
258 	struct op_event * event;
259 	size_t count;
260 
261 	count = parse_events(parsed_events, num_chosen_events, chosen_events);
262 	if (count > 1) {
263 		fprintf(stderr, "More than one event specified.\n");
264 		exit(EXIT_FAILURE);
265 	}
266 
267 	event = find_event_by_name(parsed_events[0].name, 0, 0);
268 
269 	if (!event) {
270 		fprintf(stderr, "No such event found.\n");
271 		exit(EXIT_FAILURE);
272 	}
273 
274 	printf("%d\n", event->unit->default_mask);
275 }
276 
277 
show_default_event(void)278 static void show_default_event(void)
279 {
280 	struct op_default_event_descr descr;
281 
282 	op_default_event(cpu_type, &descr);
283 
284 	if (descr.name[0] == '\0')
285 		return;
286 
287 	printf("%s:%lu:%lu:1:1\n", descr.name, descr.count, descr.um);
288 }
289 
290 
291 static int show_vers;
292 static int get_cpu_type;
293 static int check_events;
294 static int unit_mask;
295 static int get_default_event;
296 
297 static struct poptOption options[] = {
298 	{ "cpu-type", 'c', POPT_ARG_STRING, &cpu_string, 0,
299 	  "use the given CPU type", "cpu type", },
300 	{ "check-events", 'e', POPT_ARG_NONE, &check_events, 0,
301 	  "check the given event descriptions for validity", NULL, },
302 	{ "unit-mask", 'u', POPT_ARG_NONE, &unit_mask, 0,
303 	  "default unit mask for the given event", NULL, },
304 	{ "get-cpu-type", 'r', POPT_ARG_NONE, &get_cpu_type, 0,
305 	  "show the auto-detected CPU type", NULL, },
306 	{ "get-default-event", 'd', POPT_ARG_NONE, &get_default_event, 0,
307 	  "get the default event", NULL, },
308 	{ "callgraph", '\0', POPT_ARG_INT, &callgraph_depth, 0,
309 	  "use this callgraph depth", "callgraph depth", },
310 	{ "version", 'v', POPT_ARG_NONE, &show_vers, 0,
311 	   "show version", NULL, },
312 	{ "xml", 'X', POPT_ARG_NONE, &want_xml, 0,
313 	   "list events as XML", NULL, },
314 	POPT_AUTOHELP
315 	{ NULL, 0, 0, NULL, 0, NULL, NULL, },
316 };
317 
318 /**
319  * get_options - process command line
320  * @param argc  program arg count
321  * @param argv  program arg array
322  *
323  * Process the arguments, fatally complaining on error.
324  */
get_options(int argc,char const * argv[])325 static void get_options(int argc, char const * argv[])
326 {
327 	optcon = op_poptGetContext(NULL, argc, argv, options, 0);
328 
329 	if (show_vers)
330 		show_version(argv[0]);
331 
332 	/* non-option, must be a valid event name or event specs */
333 	chosen_events = poptGetArgs(optcon);
334 
335 	if(chosen_events) {
336 		num_chosen_events = 0;
337 		while (chosen_events[num_chosen_events] != NULL)
338 			num_chosen_events++;
339 	}
340 
341 	/* don't free the context now, we need chosen_events */
342 }
343 
344 
345 /** make valgrind happy */
cleanup(void)346 static void cleanup(void)
347 {
348 	int i;
349 	if (parsed_events) {
350 		for (i = 0; i < num_chosen_events; ++i) {
351 			if (parsed_events[i].name)
352 				free(parsed_events[i].name);
353 		}
354 	}
355 	op_free_events();
356 	if (optcon)
357 		poptFreeContext(optcon);
358 	if (parsed_events)
359 		free(parsed_events);
360 }
361 
362 
363 #define MAX_LINE 256
main(int argc,char const * argv[])364 int main(int argc, char const * argv[])
365 {
366 	struct list_head * events;
367 	struct list_head * pos;
368 	char const * pretty;
369 	char title[10 * MAX_LINE];
370 	char const * event_doc = "";
371 
372 	atexit(cleanup);
373 
374 	get_options(argc, argv);
375 
376 	/* usefull for testing purpose to allow to force the cpu type
377 	 * with --cpu-type */
378 	if (cpu_string) {
379 		cpu_type = op_get_cpu_number(cpu_string);
380 	} else {
381 		cpu_type = op_get_cpu_type();
382 	}
383 
384 	if (cpu_type == CPU_NO_GOOD) {
385 		fprintf(stderr, "cpu_type '%s' is not valid\n",
386 		        cpu_string ? cpu_string : "unset");
387 		fprintf(stderr, "you should upgrade oprofile or force the "
388 			"use of timer mode\n");
389 		exit(EXIT_FAILURE);
390 	}
391 
392 	parsed_events = (struct parsed_event *)xcalloc(num_chosen_events,
393 		sizeof(struct parsed_event));
394 
395 	pretty = op_get_cpu_type_str(cpu_type);
396 
397 	if (get_cpu_type) {
398 		printf("%s\n", pretty);
399 		exit(EXIT_SUCCESS);
400 	}
401 
402 	if (get_default_event) {
403 		show_default_event();
404 		exit(EXIT_SUCCESS);
405 	}
406 
407 	if (cpu_type == CPU_TIMER_INT) {
408 		if (!check_events)
409 			printf("Using timer interrupt.\n");
410 		exit(EXIT_SUCCESS);
411 	}
412 
413 	events = op_events(cpu_type);
414 
415 	if (!chosen_events && (unit_mask || check_events)) {
416 		fprintf(stderr, "No events given.\n");
417 		exit(EXIT_FAILURE);
418 	}
419 
420 	if (unit_mask) {
421 		show_unit_mask();
422 		exit(EXIT_SUCCESS);
423 	}
424 
425 	if (check_events) {
426 		resolve_events();
427 		exit(EXIT_SUCCESS);
428 	}
429 
430 	/* without --check-events, the only argument must be an event name */
431 	if (chosen_events && chosen_events[0]) {
432 		if (chosen_events[1]) {
433 			fprintf(stderr, "Too many arguments.\n");
434 			exit(EXIT_FAILURE);
435 		}
436 
437 		list_for_each(pos, events) {
438 			struct op_event * event = list_entry(pos, struct op_event, event_next);
439 
440 			if (strcmp(event->name, chosen_events[0]) == 0) {
441 				char const * map = find_mapping_for_event(event->val, cpu_type);
442 				if (map) {
443 					printf("%d %s\n", event->val, map);
444 				} else {
445 					printf("%d\n", event->val);
446 				}
447 				exit(EXIT_SUCCESS);
448 			}
449 		}
450 		fprintf(stderr, "No such event \"%s\"\n", chosen_events[0]);
451 		exit(EXIT_FAILURE);
452 	}
453 
454 	/* default: list all events */
455 
456 	switch (cpu_type) {
457 	case CPU_HAMMER:
458 		event_doc =
459 			"See BIOS and Kernel Developer's Guide for AMD Athlon and AMD Opteron Processors\n"
460 			"(26094.pdf), Section 10.2\n\n";
461 		break;
462 	case CPU_FAMILY10:
463 		event_doc =
464 			"See BIOS and Kernel Developer's Guide for AMD Family 10h Processors\n"
465 			"(31116.pdf), Section 3.14\n\n";
466 		break;
467 	case CPU_FAMILY11H:
468 		event_doc =
469 			"See BIOS and Kernel Developer's Guide for AMD Family 11h Processors\n"
470 			"(41256.pdf), Section 3.14\n\n";
471 		break;
472 	case CPU_FAMILY12H:
473 		event_doc =
474 			"See BIOS and Kernel Developer's Guide for AMD Family 12h Processors\n";
475 		break;
476 	case CPU_FAMILY14H:
477 		event_doc =
478 			"See BIOS and Kernel Developer's Guide for AMD Family 14h Processors\n";
479 		break;
480 	case CPU_FAMILY15H:
481 		event_doc =
482 			"See BIOS and Kernel Developer's Guide for AMD Family 15h Processors\n";
483 		break;
484 	case CPU_ATHLON:
485 		event_doc =
486 			"See AMD Athlon Processor x86 Code Optimization Guide\n"
487 			"(22007.pdf), Appendix D\n\n";
488 		break;
489 	case CPU_PPRO:
490 	case CPU_PII:
491 	case CPU_PIII:
492 	case CPU_P6_MOBILE:
493 	case CPU_P4:
494 	case CPU_P4_HT2:
495 	case CPU_CORE:
496 	case CPU_CORE_2:
497 	case CPU_CORE_I7:
498 	case CPU_NEHALEM:
499 	case CPU_WESTMERE:
500 	case CPU_ATOM:
501 		event_doc =
502 			"See Intel Architecture Developer's Manual Volume 3B, Appendix A and\n"
503 			"Intel Architecture Optimization Reference Manual (730795-001)\n\n";
504 		break;
505 
506 	case CPU_ARCH_PERFMON:
507 		event_doc =
508 			"See Intel 64 and IA-32 Architectures Software Developer's Manual\n"
509 			"Volume 3B (Document 253669) Chapter 18 for architectural perfmon events\n"
510 			"This is a limited set of fallback events because oprofile doesn't know your CPU\n";
511 		break;
512 
513 	case CPU_IA64:
514 	case CPU_IA64_1:
515 	case CPU_IA64_2:
516 		event_doc =
517 			"See Intel Itanium Processor Reference Manual\n"
518 			"for Software Development (Document 245320-003),\n"
519 			"Intel Itanium Processor Reference Manual\n"
520 			"for Software Optimization (Document 245473-003),\n"
521 			"Intel Itanium 2 Processor Reference Manual\n"
522 			"for Software Development and Optimization (Document 251110-001)\n\n";
523 		break;
524 	case CPU_AXP_EV4:
525 	case CPU_AXP_EV5:
526 	case CPU_AXP_PCA56:
527 	case CPU_AXP_EV6:
528 	case CPU_AXP_EV67:
529 		event_doc =
530 			"See Alpha Architecture Reference Manual\n"
531 			"http://download.majix.org/dec/alpha_arch_ref.pdf\n";
532 		break;
533 	case CPU_ARM_XSCALE1:
534 	case CPU_ARM_XSCALE2:
535 		event_doc =
536 			"See Intel XScale Core Developer's Manual\n"
537 			"Chapter 8 Performance Monitoring\n";
538 		break;
539 	case CPU_ARM_MPCORE:
540 		event_doc =
541 			"See ARM11 MPCore Processor Technical Reference Manual r1p0\n"
542 			"Page 3-70, performance counters\n";
543 		break;
544 
545 	case CPU_ARM_V6:
546 		event_doc = "See ARM11 Technical Reference Manual\n";
547   		break;
548 
549 	case CPU_ARM_V7:
550 		event_doc =
551 			"See Cortex-A8 Technical Reference Manual\n"
552 			"Cortex A8 DDI (ARM DDI 0344B, revision r1p1)\n";
553 		break;
554 
555 	case CPU_ARM_V7_CA9:
556 		event_doc =
557 			"See Cortex-A9 Technical Reference Manual\n"
558 			"Cortex A9 DDI (ARM DDI 0388E, revision r2p0)\n";
559 		break;
560 
561 	case CPU_PPC64_PA6T:
562 		event_doc =
563 			"See PA6T Power Implementation Features Book IV\n"
564 			"Chapter 7 Performance Counters\n";
565 		break;
566 
567 	case CPU_PPC64_POWER4:
568 	case CPU_PPC64_POWER5:
569 	case CPU_PPC64_POWER6:
570 	case CPU_PPC64_POWER5p:
571 	case CPU_PPC64_POWER5pp:
572 	case CPU_PPC64_970:
573 	case CPU_PPC64_970MP:
574 	case CPU_PPC64_POWER7:
575 	case CPU_PPC64_IBM_COMPAT_V1:
576 		event_doc =
577 			"Obtain PowerPC64 processor documentation at:\n"
578 			"http://www-306.ibm.com/chips/techlib/techlib.nsf/productfamilies/PowerPC\n";
579 		break;
580 
581 	case CPU_PPC64_CELL:
582 		event_doc =
583 			"Obtain Cell Broadband Engine documentation at:\n"
584 			"http://www-306.ibm.com/chips/techlib/techlib.nsf/products/Cell_Broadband_Engine\n";
585 		break;
586 
587 	case CPU_MIPS_20K:
588 		event_doc =
589 			"See Programming the MIPS64 20Kc Processor Core User's "
590 		"manual available from www.mips.com\n";
591 		break;
592 	case CPU_MIPS_24K:
593 		event_doc =
594 			"See Programming the MIPS32 24K Core "
595 			"available from www.mips.com\n";
596 		break;
597 	case CPU_MIPS_25K:
598 		event_doc =
599 			"See Programming the MIPS64 25Kf Processor Core User's "
600 			"manual available from www.mips.com\n";
601 		break;
602 	case CPU_MIPS_34K:
603 		event_doc =
604 			"See Programming the MIPS32 34K Core Family "
605 			"available from www.mips.com\n";
606 		break;
607 	case CPU_MIPS_74K:
608 		event_doc =
609 			"See Programming the MIPS32 74K Core Family "
610 			"available from www.mips.com\n";
611 		break;
612 	case CPU_MIPS_1004K:
613 		event_doc =
614 			"See Programming the MIPS32 1004K Core Family "
615 			"available from www.mips.com\n";
616 		break;
617 	case CPU_MIPS_5K:
618 		event_doc =
619 			"See Programming the MIPS64 5K Processor Core Family "
620 			"Software User's manual available from www.mips.com\n";
621 		break;
622 	case CPU_MIPS_R10000:
623 	case CPU_MIPS_R12000:
624 		event_doc =
625 			"See NEC R10000 / R12000 User's Manual\n"
626 			"http://www.necelam.com/docs/files/U10278EJ3V0UM00.pdf\n";
627 		break;
628 	case CPU_MIPS_RM7000:
629 		event_doc =
630 			"See RM7000 Family User Manual "
631 			"available from www.pmc-sierra.com\n";
632 		break;
633 	case CPU_MIPS_RM9000:
634 		event_doc =
635 			"See RM9000x2 Family User Manual "
636 			"available from www.pmc-sierra.com\n";
637 		break;
638 	case CPU_MIPS_SB1:
639 	case CPU_MIPS_VR5432:
640 		event_doc =
641 			"See NEC VR5443 User's Manual, Volume 1\n"
642 			"http://www.necelam.com/docs/files/1375_V1.pdf\n";
643 		break;
644 	case CPU_MIPS_VR5500:
645 		event_doc =
646 			"See NEC R10000 / R12000 User's Manual\n"
647 			"http://www.necel.com/nesdis/image/U16677EJ3V0UM00.pdf\n";
648 		break;
649 
650 	case CPU_MIPS_LOONGSON2:
651 		event_doc =
652 			"See loongson2 RISC Microprocessor Family Reference Manual\n";
653 		break;
654 
655 	case CPU_PPC_E500:
656 	case CPU_PPC_E500_2:
657 		event_doc =
658 			"See PowerPC e500 Core Complex Reference Manual\n"
659 			"Chapter 7: Performance Monitor\n"
660 			"Downloadable from http://www.freescale.com\n";
661 		break;
662 
663 	case CPU_PPC_E300:
664 		event_doc =
665 			"See PowerPC e300 Core Reference Manual\n"
666 			"Downloadable from http://www.freescale.com\n";
667 		break;
668 
669 	case CPU_PPC_7450:
670 		event_doc =
671 			"See MPC7450 RISC Microprocessor Family Reference "
672 			"Manual\n"
673 			"Chapter 11: Performance Monitor\n"
674 			"Downloadable from http://www.freescale.com\n";
675 		break;
676 
677 	case CPU_AVR32:
678 		event_doc =
679 			"See AVR32 Architecture Manual\n"
680 			"Chapter 6: Performance Counters\n"
681 			"http://www.atmel.com/dyn/resources/prod_documents/doc32000.pdf\n";
682 
683 		case CPU_RTC:
684 			break;
685 
686 		// don't use default, if someone add a cpu he wants a compiler warning
687 		// if he forgets to handle it here.
688 		case CPU_TIMER_INT:
689 		case CPU_NO_GOOD:
690 		case MAX_CPU_TYPE:
691 			printf("%d is not a valid processor type.\n", cpu_type);
692 			exit(EXIT_FAILURE);
693 	}
694 
695 	sprintf(title, "oprofile: available events for CPU type \"%s\"\n\n", pretty);
696 	if (want_xml)
697 		open_xml_events(title, event_doc, cpu_type);
698 	else
699 		printf("%s%s", title, event_doc);
700 
701 	list_for_each(pos, events) {
702 		struct op_event * event = list_entry(pos, struct op_event, event_next);
703 		if (want_xml)
704 			xml_help_for_event(event);
705 		else
706 			help_for_event(event);
707 	}
708 
709 	if (want_xml)
710 		close_xml_events();
711 
712 	return EXIT_SUCCESS;
713 }
714