1 /*
2 * Assembly testing and benchmarking tool
3 * Copyright (c) 2015 Henrik Gramner
4 * Copyright (c) 2008 Loren Merritt
5 *
6 * This file is part of FFmpeg.
7 *
8 * FFmpeg is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * FFmpeg is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with FFmpeg; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 *
22 * Copyright © 2018, VideoLAN and dav1d authors
23 * Copyright © 2018, Two Orioles, LLC
24 * All rights reserved.
25 *
26 * Redistribution and use in source and binary forms, with or without
27 * modification, are permitted provided that the following conditions are met:
28 *
29 * 1. Redistributions of source code must retain the above copyright notice, this
30 * list of conditions and the following disclaimer.
31 *
32 * 2. Redistributions in binary form must reproduce the above copyright notice,
33 * this list of conditions and the following disclaimer in the documentation
34 * and/or other materials provided with the distribution.
35 *
36 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
37 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
38 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
40 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
41 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
42 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
45 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
46 */
47
48 #include "config.h"
49 #include "config_components.h"
50
51 #ifndef _GNU_SOURCE
52 # define _GNU_SOURCE // for syscall (performance monitoring API), strsignal()
53 #endif
54
55 #include <signal.h>
56 #include <stdarg.h>
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <string.h>
65
66 #if HAVE_IO_H
67 #include <io.h>
68 #endif
69 #if HAVE_PRCTL
70 #include <sys/prctl.h>
71 #endif
72
73 #if defined(_WIN32) && !defined(SIGBUS)
74 /* non-standard, use the same value as mingw-w64 */
75 #define SIGBUS 10
76 #endif
77
78 #if HAVE_SETCONSOLETEXTATTRIBUTE && HAVE_GETSTDHANDLE
79 #include <windows.h>
80 #define COLOR_RED FOREGROUND_RED
81 #define COLOR_GREEN FOREGROUND_GREEN
82 #define COLOR_YELLOW (FOREGROUND_RED|FOREGROUND_GREEN)
83 #else
86 #define COLOR_YELLOW 3
87 #endif
88
89 #if HAVE_UNISTD_H
90 #include <unistd.h>
91 #endif
92
93 #if !HAVE_ISATTY
95 #endif
96
97 #if ARCH_ARM && HAVE_ARMV5TE_EXTERNAL
99
100 void (*checkasm_checked_call)(
void *
func,
int dummy, ...) = checkasm_checked_call_novfp;
101 #endif
102
103 /* Trade-off between speed and accuracy */
105
106 /* List of tests to invoke */
107 static const struct {
111 #if CONFIG_AVCODEC
112 #if CONFIG_AAC_DECODER
115 #endif
116 #if CONFIG_AAC_ENCODER
118 #endif
119 #if CONFIG_AC3DSP
121 #endif
122 #if CONFIG_ALAC_DECODER
124 #endif
125 #if CONFIG_AUDIODSP
127 #endif
128 #if CONFIG_BLOCKDSP
130 #endif
131 #if CONFIG_BSWAPDSP
133 #endif
134 #if CONFIG_DCA_DECODER
136 #endif
137 #if CONFIG_EXR_DECODER
139 #endif
140 #if CONFIG_FDCTDSP
142 #endif
143 #if CONFIG_FLAC_DECODER
145 #endif
146 #if CONFIG_FMTCONVERT
148 #endif
149 #if CONFIG_G722DSP
151 #endif
152 #if CONFIG_H263DSP
154 #endif
155 #if CONFIG_H264CHROMA
157 #endif
158 #if CONFIG_H264DSP
160 #endif
161 #if CONFIG_H264PRED
163 #endif
164 #if CONFIG_H264QPEL
166 #endif
167 #if CONFIG_HEVC_DECODER
173 #endif
174 #if CONFIG_HUFFYUV_DECODER
176 #endif
177 #if CONFIG_IDCTDSP
179 #endif
180 #if CONFIG_JPEG2000_DECODER
182 #endif
183 #if CONFIG_LLAUDDSP
185 #endif
186 #if CONFIG_HUFFYUVDSP
188 #endif
189 #if CONFIG_LLVIDENCDSP
191 #endif
192 #if CONFIG_LPC
194 #endif
195 #if CONFIG_ME_CMP
197 #endif
198 #if CONFIG_MPEGVIDEOENC
200 #endif
201 #if CONFIG_OPUS_DECODER
203 #endif
204 #if CONFIG_PIXBLOCKDSP
206 #endif
207 #if CONFIG_RV34DSP
209 #endif
210 #if CONFIG_RV40_DECODER
212 #endif
213 #if CONFIG_SVQ1_ENCODER
215 #endif
216 #if CONFIG_TAK_DECODER
218 #endif
219 #if CONFIG_UTVIDEO_DECODER
221 #endif
222 #if CONFIG_V210_DECODER
224 #endif
225 #if CONFIG_V210_ENCODER
227 #endif
228 #if CONFIG_VC1DSP
230 #endif
231 #if CONFIG_VP8DSP
233 #endif
234 #if CONFIG_VP9_DECODER
236 #endif
237 #if CONFIG_VIDEODSP
239 #endif
240 #if CONFIG_VORBIS_DECODER
242 #endif
243 #if CONFIG_VVC_DECODER
246 #endif
247 #endif
248 #if CONFIG_AVFILTER
249 #if CONFIG_AFIR_FILTER
251 #endif
252 #if CONFIG_BLEND_FILTER
254 #endif
255 #if CONFIG_BWDIF_FILTER
257 #endif
258 #if CONFIG_COLORSPACE_FILTER
260 #endif
261 #if CONFIG_EQ_FILTER
263 #endif
264 #if CONFIG_GBLUR_FILTER
266 #endif
267 #if CONFIG_HFLIP_FILTER
269 #endif
270 #if CONFIG_NLMEANS_FILTER
272 #endif
273 #if CONFIG_THRESHOLD_FILTER
275 #endif
276 #if CONFIG_SOBEL_FILTER
278 #endif
279 #endif
280 #if CONFIG_SWSCALE
287 #endif
288 #if CONFIG_AVUTIL
293 #endif
295 };
296
297 /* List of cpu flags to check */
298 static const struct {
303 #if ARCH_AARCH64
308 #elif ARCH_ARM
316 #elif ARCH_PPC
320 #elif ARCH_RISCV
330 #elif ARCH_MIPS
333 #elif ARCH_X86
352 #elif ARCH_LOONGARCH
355 #endif
357 };
358
366
367 /* Binary search tree node */
371 uint8_t
color;
/* 0 = red, 1 = black */
374
375 /* Internal state */
376 static struct {
385
386 /* perf */
389
398
399 /* PRNG state */
401
402 /* float compare support code */
404 {
406 }
407
409 {
411
414
416 // handle -0.0 == +0.0
418 }
419
420 if (llabs((
int64_t)x.
i - y.
i) <= max_ulp)
421 return 1;
422
423 return 0;
424 }
425
428 {
430
431 for (
i = 0;
i <
len;
i++) {
433 return 0;
434 }
435 return 1;
436 }
437
439 {
441 if (abs_diff < eps)
442 return 1;
443
444 fprintf(stderr,
"test failed comparing %g with %g (abs diff=%g with EPS=%g)\n",
a,
b, abs_diff, eps);
445
446 return 0;
447 }
448
451 {
453
454 for (
i = 0;
i <
len;
i++) {
456 return 0;
457 }
458 return 1;
459 }
460
462 {
464 }
465
467 unsigned max_ulp,
unsigned len)
468 {
470
471 for (
i = 0;
i <
len;
i++) {
473 return 0;
474 }
475 return 1;
476 }
477
479 {
480 double abs_diff =
fabs(
a -
b);
481
482 return abs_diff < eps;
483 }
484
487 {
489
490 for (
i = 0;
i <
len;
i++) {
492 return 0;
493 }
494 return 1;
495 }
496
497 /* Print colored text to stderr if the terminal supports it */
499 {
502
503 #if HAVE_SETCONSOLETEXTATTRIBUTE && HAVE_GETSTDHANDLE
504 static HANDLE con;
505 static WORD org_attributes;
506
508 CONSOLE_SCREEN_BUFFER_INFO con_info;
509 con = GetStdHandle(STD_ERROR_HANDLE);
510 if (con && con != INVALID_HANDLE_VALUE && GetConsoleScreenBufferInfo(con, &con_info)) {
511 org_attributes = con_info.wAttributes;
513 } else
515 }
517 SetConsoleTextAttribute(con, (org_attributes & 0xfff0) | (
color & 0x0f));
518 #else
520 const char *term = getenv("TERM");
522 }
524 fprintf(stderr,
"\x1b[%d;3%dm", (
color & 0x08) >> 3,
color & 0x07);
525 #endif
526
528 vfprintf(stderr, fmt,
arg);
530
532 #if HAVE_SETCONSOLETEXTATTRIBUTE && HAVE_GETSTDHANDLE
533 SetConsoleTextAttribute(con, org_attributes);
534 #else
535 fprintf(stderr, "\x1b[0m");
536 #endif
537 }
538 }
539
540 /* Deallocate a tree */
542 {
545 while (v) {
547 free(v);
548 v = next;
549 }
550
554 }
555 }
556
557 /* Allocate a zero-initialized block, clean up and exit on failure */
559 {
560 void *ptr = calloc(1,
size);
561 if (!ptr) {
562 fprintf(stderr, "checkasm: malloc failed\n");
564 exit(1);
565 }
566 return ptr;
567 }
568
569 /* Get the suffix of the specified cpu flag */
571 {
573
576 return cpus[
i].suffix;
577
578 return "c";
579 }
580
582 {
583 return *(
const uint16_t*)
a - *(
const uint16_t*)
b;
584 }
585
586 /* Measure the overhead of the timing code (in decicycles) */
588 {
589 uint16_t nops[10000];
592
593 uint64_t t = 0;
594 for (
i = 0;
i < 10000;
i++) {
598 }
599
600 qsort(nops, 10000,
sizeof(uint16_t),
cmp_nop);
601 for (
i = 2500;
i < 7500;
i++)
603
604 return nop_sum / 500;
605 }
606
608 {
611 if (cycles > 0.0)
612 return cycles / 4.0; /* 4 calls per iteration */
613 }
614 return 0.0;
615 }
616
617 /* Print benchmark results */
619 {
624 double decicycles;
625
627
628 do {
633 const char sep =
state.csv ?
',' :
'\t';
634 printf(
"%s%c%s%c%.1f\n",
f->name, sep,
636 decicycles / 10.0);
637 } else {
638 const int pad_length = 10 + 50 -
640 const double ratio = decicycles ?
641 baseline / decicycles : 0.0;
643 decicycles / 10.0, ratio);
644 }
645 }
646 }
while ((v = v->
next));
647
649 }
650 }
651
652 /* ASCIIbetical sort except preserving natural order for numbers */
654 {
655 const char *start =
a;
656 int ascii_diff, digit_diff;
657
658 for (; !(ascii_diff = *(
const unsigned char*)
a - *(
const unsigned char*)
b) && *
a;
a++,
b++);
660
662 return digit_diff;
663
664 return ascii_diff;
665 }
666
667 /* Perform a tree rotation in the specified direction and return the new root */
669 {
671 f->child[dir^1] =
r->child[dir];
676 }
677
678 #define is_red(f) ((f) && !(f)->color)
679
680 /* Balance a left-leaning red-black tree at the specified node */
682 {
684
687 f->child[0]->color =
f->child[1]->color = 1;
688 }
689
694 }
695
696 /* Get a node with the specified name, creating it if it doesn't exist */
698 {
700
702 /* Search the tree for a matching node */
706
707 /* Rebalance the tree on the way up if a new node was inserted */
708 if (!
f->versions.func)
710 }
711 } else {
712 /* Allocate and insert a new node into the tree */
713 int name_length = strlen(
name);
715 memcpy(
f->name,
name, name_length + 1);
716 }
717
719 }
720
722
723 /* Crash handling: attempt to catch crashes and handle them
724 * gracefully instead of just aborting abruptly. */
725 #ifdef _WIN32
726 #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
729
730 if (!
state.catch_signals)
731 return EXCEPTION_CONTINUE_SEARCH;
732
733 switch (e->ExceptionRecord->ExceptionCode) {
734 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
735 case EXCEPTION_INT_DIVIDE_BY_ZERO:
737 break;
738 case EXCEPTION_ILLEGAL_INSTRUCTION:
739 case EXCEPTION_PRIV_INSTRUCTION:
741 break;
742 case EXCEPTION_ACCESS_VIOLATION:
743 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
744 case EXCEPTION_DATATYPE_MISALIGNMENT:
745 case EXCEPTION_STACK_OVERFLOW:
747 break;
748 case EXCEPTION_IN_PAGE_ERROR:
750 break;
751 default:
752 return EXCEPTION_CONTINUE_SEARCH;
753 }
754 state.catch_signals = 0;
756 return EXCEPTION_CONTINUE_EXECUTION; /* never reached, but shuts up gcc */
757 }
758 #endif
759 #else
761
764 .sa_flags = SA_RESETHAND,
765 };
766
768 if (
state.catch_signals) {
769 state.catch_signals = 0;
772 }
773 }
774 #endif
775
776 /* Compares a string with a wildcard pattern. */
778 {
779 const char *wild = strchr(pattern, '*');
780 if (wild) {
781 const size_t len = wild - pattern;
782 if (strncmp(str, pattern,
len))
return 1;
783 while (*++wild == '*');
784 if (!*wild) return 0;
787 return !*str;
788 }
789 return strcmp(str, pattern);
790 }
791
792 /* Perform tests and benchmarks for the specified cpu flag if supported by the host */
794 {
795 int old_cpu_flag =
state.cpu_flag;
796
797 flag |= old_cpu_flag;
801
802 if (!
flag ||
state.cpu_flag != old_cpu_flag) {
804
808 continue;
811 }
812 }
813 }
814
815 /* Print the name of the current CPU flag, but only do it once */
817 {
818 if (
state.cpu_flag_name) {
821 }
822 }
823
824 #if CONFIG_LINUX_PERF
825 static int bench_init_linux(void)
826 {
827 struct perf_event_attr attr = {
828 .type = PERF_TYPE_HARDWARE,
829 .size = sizeof(struct perf_event_attr),
830 .
config = PERF_COUNT_HW_CPU_CYCLES,
831 .disabled = 1, // start counting only on demand
832 .exclude_kernel = 1,
833 .exclude_hv = 1,
834 #if !ARCH_X86
835 .exclude_guest = 1,
836 #endif
837 };
838
839 fprintf(stderr, "benchmarking with Linux Perf Monitoring API\n");
840
841 state.sysfd = syscall(__NR_perf_event_open, &attr, 0, -1, -1, 0);
842 if (
state.sysfd == -1) {
843 perror("perf_event_open");
844 return -1;
845 }
846 return 0;
847 }
848 #elif CONFIG_MACOS_KPERF
849 static int bench_init_kperf(void)
850 {
852 return 0;
853 }
854 #else
856 {
857 #ifdef AV_READ_TIME
862 } else {
863 fprintf(stderr, "checkasm: unable to execute platform specific timer\n");
864 return -1;
865 }
866 fprintf(stderr, "benchmarking with native FFmpeg timers\n");
867 return 0;
868 #else
869 fprintf(stderr, "checkasm: --bench is not supported on your system\n");
870 return -1;
871 #endif
872 }
873 #endif
874
876 {
877 #if CONFIG_LINUX_PERF
878 int ret = bench_init_linux();
879 #elif CONFIG_MACOS_KPERF
880 int ret = bench_init_kperf();
881 #else
883 #endif
886
888 fprintf(stderr,
"nop: %d.%d\n",
state.nop_time/10,
state.nop_time%10);
889 return 0;
890 }
891
893 {
894 #if CONFIG_LINUX_PERF
896 #endif
897 }
898
900 {
901 fprintf(stderr,
902 "Usage: %s [options...] [seed]\n"
903 " --test=<pattern> Run specific test.\n"
904 " --bench Run benchmark.\n"
905 " --csv, --tsv Output results in rows of comma or tab separated values.\n"
906 " --runs=<ptwo> Manual number of benchmark iterations to run 2**<ptwo>.\n"
907 " --verbose Increase verbosity.\n",
908 path);
909 return 1;
910 }
911
912 int main(
int argc,
char *argv[])
913 {
916
917 #ifdef _WIN32
918 #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
920 #endif
921 #else
926 #endif
927 #if HAVE_PRCTL && defined(PR_SET_UNALIGN)
928 prctl(PR_SET_UNALIGN, PR_UNALIGN_SIGBUS);
929 #endif
930 #if ARCH_ARM && HAVE_ARMV5TE_EXTERNAL
932 checkasm_checked_call = checkasm_checked_call_vfp;
933 #endif
934
936 fprintf(stderr, "checkasm: no tests to perform\n");
937 return 0;
938 }
939
940 for (
i = 1;
i < argc;
i++) {
941 const char *
arg = argv[
i];
942 unsigned long l;
943 char *end;
944
945 if (!strncmp(
arg,
"--bench", 7)) {
947 return 1;
950 state.bench_pattern_len = strlen(
state.bench_pattern);
951 } else
952 state.bench_pattern =
"*";
953 }
else if (!strncmp(
arg,
"--test=", 7)) {
955 }
else if (!strcmp(
arg,
"--csv")) {
957 }
else if (!strcmp(
arg,
"--tsv")) {
959 }
else if (!strcmp(
arg,
"--verbose") || !strcmp(
arg,
"-v")) {
961 }
else if (!strncmp(
arg,
"--runs=", 7)) {
962 l = strtoul(
arg + 7, &end, 10);
963 if (*end == '0円') {
964 if (l > 30) {
965 fprintf(stderr, "checkasm: error: runs exponent must be within the range 0 <= 30\n");
967 }
969 } else {
970 return usage(argv[0]);
971 }
972 }
else if ((l = strtoul(
arg, &end, 10)) <= UINT_MAX &&
973 *end == '0円') {
975 } else {
976 return usage(argv[0]);
977 }
978 }
979
980 fprintf(stderr,
"checkasm: using random seed %u\n",
seed);
982
983 if (
state.bench_pattern)
985
989
990 if (
state.num_failed) {
991 fprintf(stderr,
"checkasm: %d of %d tests have failed\n",
state.num_failed,
state.num_checked);
993 } else {
994 fprintf(stderr,
"checkasm: all %d tests passed\n",
state.num_checked);
995 if (
state.bench_pattern) {
997 }
998 }
999
1003 }
1004
1005 /* Decide whether or not the specified function needs to be tested and
1006 * allocate/initialize data structures if needed. Returns a pointer to a
1007 * reference function if the function should be tested, otherwise NULL */
1009 {
1010 char name_buf[256];
1013 int name_length;
1015
1019
1020 if (!
func || name_length <= 0 || name_length >=
sizeof(name_buf))
1022
1024 state.funcs->color = 1;
1025 v = &
state.current_func->versions;
1026
1029 do {
1030 /* Only test functions that haven't already been tested */
1033
1036
1037 prev = v;
1038 }
while ((v = v->
next));
1039
1041 }
1042
1046 state.current_func_ver = v;
1047
1049 state.num_checked++;
1050
1052 }
1053
1054 /* Decide whether or not the current function needs to be benchmarked */
1056 {
1057 return !
state.num_failed &&
state.bench_pattern &&
1059 }
1060
1061 /* Indicate that the current test has failed */
1063 {
1064 if (
state.current_func_ver &&
state.current_func_ver->cpu &&
1065 state.current_func_ver->ok)
1066 {
1068
1070 fprintf(stderr,
" %s_%s (",
state.current_func->name,
cpu_suffix(
state.current_func_ver->cpu));
1072 vfprintf(stderr, msg,
arg);
1074 fprintf(stderr, ")\n");
1075
1076 state.current_func_ver->ok = 0;
1078 }
1079 }
1080
1082 state.catch_signals = enabled;
1083 }
1084
1087 #ifdef __GLIBC__
1089 #else
1091 s == SIGILL ?
"illegal instruction" :
1092 s == SIGBUS ?
"bus error" :
1093 "segmentation fault");
1094 #endif
1095 }
1097 }
1098
1099 /* Get the benchmark context of the current function */
1101 {
1103 memset(perf, 0, sizeof(*perf));
1105 return perf;
1106 }
1107
1108 /* Print the outcome of all tests performed since the last time this function was called */
1110 {
1111 static int prev_checked, prev_failed, max_length;
1112
1113 if (
state.num_checked > prev_checked) {
1114 int pad_length = max_length + 4;
1116
1118 pad_length -= fprintf(stderr,
" - %s.",
state.current_test_name);
1120 pad_length -= vfprintf(stderr,
name,
arg);
1122 fprintf(stderr,
"%*c",
FFMAX(pad_length, 0) + 2,
'[');
1123
1124 if (
state.num_failed == prev_failed)
1126 else
1128 fprintf(stderr, "]\n");
1129
1130 prev_checked =
state.num_checked;
1131 prev_failed =
state.num_failed;
1132 }
else if (!
state.cpu_flag) {
1133 /* Calculate the amount of padding required to make the output vertically aligned */
1134 int length = strlen(
state.current_test_name);
1136
1140
1141 if (length > max_length)
1142 max_length = length;
1143 }
1144 }
1145
1146 #define DEF_CHECKASM_CHECK_FUNC(type, fmt) \
1147 int checkasm_check_##type(const char *file, int line, \
1148 const type *buf1, ptrdiff_t stride1, \
1149 const type *buf2, ptrdiff_t stride2, \
1150 int w, int h, const char *name) \
1151 { \
1152 int y = 0; \
1153 stride1 /= sizeof(*buf1); \
1154 stride2 /= sizeof(*buf2); \
1155 for (y = 0; y < h; y++) \
1156 if (memcmp(&buf1[y*stride1], &buf2[y*stride2], w*sizeof(*buf1))) \
1157 break; \
1158 if (y == h) \
1159 return 0; \
1160 checkasm_fail_func("%s:%d", file, line); \
1161 if (!state.verbose) \
1162 return 1; \
1163 fprintf(stderr, "%s:\n", name); \
1164 while (h--) { \
1165 for (int x = 0; x < w; x++) \
1166 fprintf(stderr, " " fmt, buf1[x]); \
1167 fprintf(stderr, " "); \
1168 for (int x = 0; x < w; x++) \
1169 fprintf(stderr, " " fmt, buf2[x]); \
1170 fprintf(stderr, " "); \
1171 for (int x = 0; x < w; x++) \
1172 fprintf(stderr, "%c", buf1[x] != buf2[x] ? 'x' : '.'); \
1173 buf1 += stride1; \
1174 buf2 += stride2; \
1175 fprintf(stderr, "\n"); \
1176 } \
1177 return 1; \
1178 }
1179