1/*
2 * Copyright (c) 2010 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1.  Redistributions of source code must retain the above copyright
11 *     notice, this list of conditions and the following disclaimer.
12 * 2.  Redistributions in binary form must reproduce the above copyright
13 *     notice, this list of conditions and the following disclaimer in the
14 *     documentation and/or other materials provided with the distribution.
15 * 3.  Neither the name of Apple Inc. ("Apple") nor the names of its
16 *     contributors may be used to endorse or promote products derived from
17 *     this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * Portions of this software have been released under the following terms:
31 *
32 * (c) Copyright 1989-1993 OPEN SOFTWARE FOUNDATION, INC.
33 * (c) Copyright 1989-1993 HEWLETT-PACKARD COMPANY
34 * (c) Copyright 1989-1993 DIGITAL EQUIPMENT CORPORATION
35 *
36 * To anyone who acknowledges that this file is provided "AS IS"
37 * without any express or implied warranty:
38 * permission to use, copy, modify, and distribute this file for any
39 * purpose is hereby granted without fee, provided that the above
40 * copyright notices and this notice appears in all source code copies,
41 * and that none of the names of Open Software Foundation, Inc., Hewlett-
42 * Packard Company or Digital Equipment Corporation be used
43 * in advertising or publicity pertaining to distribution of the software
44 * without specific, written prior permission.  Neither Open Software
45 * Foundation, Inc., Hewlett-Packard Company nor Digital
46 * Equipment Corporation makes any representations about the suitability
47 * of this software for any purpose.
48 *
49 * Copyright (c) 2007, Novell, Inc. All rights reserved.
50 * Redistribution and use in source and binary forms, with or without
51 * modification, are permitted provided that the following conditions
52 * are met:
53 *
54 * 1.  Redistributions of source code must retain the above copyright
55 *     notice, this list of conditions and the following disclaimer.
56 * 2.  Redistributions in binary form must reproduce the above copyright
57 *     notice, this list of conditions and the following disclaimer in the
58 *     documentation and/or other materials provided with the distribution.
59 * 3.  Neither the name of Novell Inc. nor the names of its contributors
60 *     may be used to endorse or promote products derived from this
61 *     this software without specific prior written permission.
62 *
63 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
64 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
65 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
66 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY
67 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
68 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
69 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
70 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
71 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
72 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
73 *
74 * @APPLE_LICENSE_HEADER_END@
75 */
76
77/*
78**
79**  NAME
80**
81**      perf.c
82**
83**  FACILITY:
84**
85**      Remote Procedure Call (RPC)
86**
87**  ABSTRACT:
88**
89**  Server manager routines for the perf interface of the performance and
90**  system exerciser.
91**
92**
93*/
94#include <stdlib.h>
95#include <string.h>
96#include <malloc.h>
97#include <unistd.h>
98#include <sys/file.h>
99#include <sys/fcntl.h>
100#include <sys/wait.h>
101#include <perf_c.h>
102#include <perf_p.h>
103
104void print_binding_info(char *text, handle_t h);
105
106static int n_calls = 0,
107    n_brd = 0,
108    n_maybe = 0,
109    n_brd_maybe = 0;
110
111static struct
112{
113    unsigned32      count;
114    uuid_p_t        uuid[3];
115} object_vec =
116{
117    3,
118    {
119        &NilObj,
120        &NilTypeObj,
121        (uuid_p_t) &FooObj1
122    }
123};
124
125
126/***************************************************************************/
127
128static void common()
129{
130    n_calls++;
131}
132
133/***************************************************************************/
134
135void perf_init
136(
137    handle_t                h
138)
139{
140    print_binding_info ("perf_init", h);
141    n_calls = 0;
142}
143
144/***************************************************************************/
145
146void perf_info
147(
148    handle_t                h __attribute__(unused),
149    unsigned32           *n,
150    unsigned32           *nm,
151    unsigned32           *nb,
152    unsigned32           *nbm
153)
154{
155    *n = n_calls;
156    *nm = n_maybe;
157    *nb = n_brd;
158    *nbm = n_brd_maybe;
159}
160
161/***************************************************************************/
162
163void perf_null
164(
165    handle_t                h __attribute__(unused)
166)
167{
168    common();
169}
170
171/***************************************************************************/
172
173void perf_null_idem
174(
175    handle_t                h __attribute__(unused)
176)
177{
178    common();
179}
180
181/***************************************************************************/
182
183void perf_in
184(
185    handle_t                h __attribute__(unused),
186    perf_data_t             d,
187    unsigned32           l,
188    idl_boolean             verify,
189    unsigned32           *sum
190)
191{
192    unsigned long           i, rsum;
193
194    common();
195
196    if (! verify)
197    {
198        return;
199    }
200
201    for (i = 0, rsum = 0; i < l; i++)
202    {
203        rsum += d[i];
204    }
205
206    *sum = rsum;
207}
208
209/***************************************************************************/
210
211void perf_in_idem
212(
213    handle_t                h __attribute__(unused),
214    perf_data_t             d,
215    unsigned32           l,
216    idl_boolean             verify,
217    unsigned32           *sum
218)
219{
220    perf_in(h, d, l, verify, sum);
221}
222
223/***************************************************************************/
224
225void perf_out
226(
227    handle_t                h __attribute__(unused),
228    perf_data_t             d,
229    unsigned32           *l,
230    unsigned32           m,
231    unsigned32           pass,
232    idl_boolean             verify
233)
234{
235    unsigned long           i;
236
237    common();
238
239    if (! verify)
240    {
241        return;
242    }
243
244    for (i = 0; i < *l; i++)
245    {
246        d[i] = i * perf_magic * pass;
247    }
248
249    *l = m;
250}
251
252/***************************************************************************/
253
254void perf_out_idem
255(
256    handle_t                h,
257    perf_data_t             d,
258    unsigned32           *l,
259    unsigned32           m,
260    unsigned32           pass,
261    idl_boolean             verify
262)
263{
264    perf_out(h, d, l, m, pass, verify);
265}
266
267/***************************************************************************/
268
269void perf_brd
270(
271    handle_t                h,
272    idl_char                *name
273)
274{
275    print_binding_info ("perf_brd", h);
276    common();
277    n_brd++;
278    gethostname(name, 256);
279}
280
281/***************************************************************************/
282
283void perf_maybe
284(
285    handle_t                h
286)
287{
288    print_binding_info ("perf_maybe", h);
289    common();
290    n_maybe++;
291}
292
293/***************************************************************************/
294
295void perf_brd_maybe
296(
297    handle_t                h
298)
299{
300    print_binding_info ("perf_brd_maybe", h);
301    common();
302    n_brd_maybe++;
303}
304
305/***************************************************************************/
306
307void perf_fp_test
308(
309    handle_t                h __attribute__(unused),
310    float                   *f1,
311    float                   *f2,
312    double                  d1,
313    double                  d2,
314    float                   *o1,
315    double                  *o2
316)
317{
318    common();
319
320    UNMARSHALL_DOUBLE(d1);
321    UNMARSHALL_DOUBLE(d2);
322
323    *o1 = (*f1 / *f2) * (d1 / d2);
324    *o2 = (*f2 / *f1) * (d2 / d1);
325
326    MARSHALL_DOUBLE(*o2);
327}
328
329/***************************************************************************/
330
331static boolean32            got_fwd_bindings = false;
332static rpc_binding_vector_p_t fwd_bv;
333
334void perf_register_b
335(
336    handle_t                h,
337    idl_boolean             global __attribute__(unused),
338    unsigned32              *st
339)
340{
341    unsigned_char_p_t       bstr;
342    unsigned_char_p_t       protseq;
343    unsigned int                     i;
344    unsigned32              xst;
345    extern rpc_if_handle_t    perfb_v1_0_s_ifspec;
346    extern perfb_v1_0_epv_t   perfb_mgr_epv;
347    extern rpc_binding_vector_p_t bv;
348
349    print_binding_info ("perf_register_b", h);
350
351    if (! got_fwd_bindings)
352    {
353#ifndef REUSE_SERVER_BINDINGS
354        /*
355         * Create a new endpoint to receive the request on.  Just use
356         * a single protseq; the first one in the server's binding list
357         * will do.
358         */
359
360        rpc_binding_to_string_binding(bv->binding_h[0], &bstr, st);
361        rpc_string_binding_parse(bstr, NULL, &protseq, NULL, NULL, NULL, st);
362        rpc_server_use_protseq(protseq, 1, st);
363        if (*st != 0)
364        {
365            fprintf(stderr, "*** Can't use_protseq - %s\n",
366                    error_text(*st));
367            return;
368        }
369        rpc_string_free(&protseq, st);
370        rpc_string_free(&bstr, st);
371
372        /*
373         * Need to come up with a vector of handles to the newly created
374         * endpoint.  This is a real hack (the ordering of the handles
375         * is presumptious), but it should work for the purposes of this
376         * test.  The correct thing to do would be to convert all the bindings
377         * to binding-strings and filter out all duplicates.
378         */
379
380        rpc_server_inq_bindings(&fwd_bv, st);
381        if (fwd_bv->count <= bv->count)
382        {
383            fprintf(stderr, "*** No additional bindings created for forwarding?\n");
384            *st = -1;   /* !!! */
385            return;
386        }
387
388        /*
389         * Free all the pre-existing handles and shuffle the new ones to the
390         * beginning of the vector (adjust the count appropriately).
391         */
392
393        for (i = 0; i < bv->count; i++)
394            rpc_binding_free(&fwd_bv->binding_h[i], st);
395
396        for (i = bv->count; i < fwd_bv->count; i++)
397        {
398            rpc_binding_copy(fwd_bv->binding_h[i],
399                    &fwd_bv->binding_h[i-bv->count], st);
400            rpc_binding_free(&fwd_bv->binding_h[i], st);
401        }
402        fwd_bv->count = i - bv->count;
403#else
404        /*
405         * Just use the original bindings... this is slightly unorthodox
406         * (not going fully through the effort to duplicate the binding
407         * references) but it should work since neither the original nor
408         * the duplicate bindings are freed.
409         */
410        fwd_bv = bv;
411#endif
412        printf("+ Got bindings:\n");
413        for (i = 0; i < fwd_bv->count; i++)
414        {
415            rpc_binding_to_string_binding(fwd_bv->binding_h[i], &bstr, st);
416            printf("    %s\n", (char *)bstr);
417            rpc_string_free(&bstr, st);
418        }
419        got_fwd_bindings = true;
420    }
421
422    rpc_server_register_if(perfb_v1_0_s_ifspec,
423                    (uuid_p_t) NULL, (rpc_mgr_epv_t) &perfb_mgr_epv, st);
424    if (*st != 0)
425    {
426        fprintf(stderr, "*** Can't rpc_server_register_if - %s\n",
427                error_text (*st));
428        return;
429    }
430
431    rpc_ep_register(perfb_v1_0_s_ifspec, fwd_bv, (uuid_vector_p_t) &object_vec,
432            (unsigned_char_p_t)"perfb forwarding test manager", st);
433
434    if (*st != 0)
435    {
436        fprintf(stderr, "*** Can't rpc_ep_register - %s\n",
437                error_text (*st));
438        rpc_server_unregister_if(perfb_v1_0_s_ifspec, (uuid_p_t) NULL, &xst);
439        if (xst != 0)
440        {
441            fprintf(stderr, "*** Can't rpc_server_unregister_if - %s\n",
442                   error_text(xst));
443        }
444        return;
445    }
446}
447
448/***************************************************************************/
449
450void perf_unregister_b
451(
452    handle_t                h,
453    unsigned32              *st
454)
455{
456    unsigned32              st1, st2;
457    extern rpc_if_handle_t  perfb_v1_0_s_ifspec;
458
459    print_binding_info ("perf_unregister_b", h);
460
461    if (!got_fwd_bindings)
462    {
463        fprintf(stderr, "*** perf_unregister_b - no fwd bindings\n");
464        *st = -1;   /* !!! */
465    }
466
467    rpc_ep_unregister(perfb_v1_0_s_ifspec, fwd_bv,
468                            (uuid_vector_p_t) &object_vec, &st1);
469    if (st1 != 0)
470    {
471        fprintf(stderr, "*** Can't rpc_ep_unregister - %s\n",
472                error_text (st1));
473    }
474
475    rpc_server_unregister_if(perfb_v1_0_s_ifspec, (uuid_p_t) NULL, &st2);
476    if (st2 != 0)
477    {
478        fprintf(stderr, "*** Can't rpc_server_unregister_if - %s\n",
479               error_text(st2));
480    }
481
482    *st = (st1 != 0) ? st1 : st2;
483}
484
485
486/***************************************************************************/
487
488void perf_exception
489(
490    handle_t                h
491)
492{
493
494    print_binding_info ("perf_exception", h);
495
496    /*
497     * Here we raise an exception which the server stub will
498     * catch, and hopefully, bounce back to the client.
499     *
500     * At various times, this code did a floating point divide by
501     * zero, and a kill (self, SIGFPE).  In the current DCE 1.0.2
502     * implementation, the threads package terminates the process
503     * upon synchronous terminating signals, and we cannot easily
504     * catch them. Therefore do a simple RAISE here.
505     */
506
507    RAISE (exc_e_intdiv);
508
509}
510
511/***************************************************************************/
512
513static void slow
514(
515    handle_t                h __attribute__(unused),
516    perf_slow_mode_t        mode,
517    unsigned32           secs
518)
519{
520    long                    start_time;
521
522    common();
523
524    TRY
525    {
526        start_time = time(0l);
527
528        switch ((int) mode)
529        {
530            case perf_slow_sleep:
531                printf("+ Sleeping for %lu seconds...\n", secs);
532                SLEEP(secs);
533                printf("    ...awake!\n");
534                break;
535
536            case perf_slow_cpu:
537                printf("+ CPU looping for %lu seconds...\n", secs);
538                while ((unsigned32)(time(0) - start_time) < secs)
539                {
540                    ;
541                }
542                printf("    ...done!\n");
543                break;
544
545            case perf_slow_io:
546            {
547                char *heap = (char *) malloc(secs);
548                int f, n;
549                unsigned long i;
550                static char buf[] = "0123456789ABCDE\n";
551                char *t;
552                char TempFileName [] = "/tmp/perfXXXXXX";
553
554                t = (char *) mktemp(TempFileName);
555                printf("+ Writing file \"%s\" (size=%ld bytes)\n", t, secs);
556                f = open(t, (O_TRUNC | O_RDWR | O_CREAT), 0777);
557                if (f < 0)
558                {
559                    perror("Can't create temp file");
560                    goto DONE;
561                }
562
563                for (i = 0; i < secs; i++)
564                {
565                    n = write(f, buf, sizeof buf);
566                    if (n != sizeof buf)
567                    {
568                        perror("Write failed");
569                        goto DONE;
570                    }
571                }
572                for (i = 0; i < 10; i++)
573                {
574                    lseek(f, 0L, 0);
575                    n = read(f, heap, (int) secs);
576                    if (n < 0)
577                    {
578                        perror("Read failed");
579                        goto DONE;
580                    }
581                    printf("    ...read %d bytes (%ld)\n", n, i);
582                }
583
584DONE:
585                printf("    ...done!\n");
586                free(heap);
587                if (f >= 0)
588                    close(f);
589                unlink(t);
590                break;
591            }
592            case perf_slow_fork_sleep:
593            {
594                pid_t   cpid;
595                pid_t   pid;
596                char    buf[16];
597                printf("+ Forking sleep for %lu seconds...\n", secs);
598                sprintf(buf, "%lu", secs);
599                cpid = fork();
600                if (cpid == 0)
601                {
602                    /* Child */
603                    execlp("sleep", "sleep", buf, 0);
604                }
605                else
606                {
607                    /* Parent */
608                    /*
609                     * CMA doesn't wrap waitpid()!
610                     */
611                    pid = waitpid(cpid, NULL, WNOHANG);
612                    if (pid != -1)
613                    {
614                        SLEEP(secs-1);
615                        waitpid(cpid, NULL, 0);
616                    }
617                }
618                printf("    ...awake!\n");
619                break;
620            }
621        }
622    }
623    CATCH(cma_e_alerted)
624    {
625        printf("    ...'cancel' exception caught\n");
626        RERAISE;
627    }
628    CATCH_ALL
629    {
630        printf("    ...unknown exception caught\n");
631        RERAISE;
632    }
633    ENDTRY
634}
635
636/***************************************************************************/
637
638void perf_null_slow
639(
640    handle_t                h,
641    perf_slow_mode_t        mode,
642    unsigned32           secs
643)
644{
645  int oc = 0;
646
647  if (mode == perf_slow_cpu)
648    oc = pthread_setcancel(CANCEL_OFF);
649
650  print_binding_info ("perf_null_slow", h);
651  slow (h, mode, secs);
652
653  if (mode == perf_slow_cpu)
654    pthread_setcancel(oc);
655
656}
657
658/***************************************************************************/
659
660void perf_null_slow_idem
661(
662    handle_t                h,
663    perf_slow_mode_t        mode,
664    unsigned32           secs
665)
666{
667  int oc =0;
668
669  if (mode == perf_slow_cpu)
670    oc = pthread_setcancel(CANCEL_OFF);
671
672  print_binding_info ("perf_null_slow_idem", h);
673  slow(h, mode, secs);
674
675  if (mode == perf_slow_cpu)
676    pthread_setcancel(oc);
677
678}
679
680/***************************************************************************/
681
682void perf_shutdown
683(
684    handle_t                h
685)
686{
687    unsigned32          st;
688
689    print_binding_info ("perf_shutdown", h);
690    common();
691    rpc_mgmt_stop_server_listening (NULL, &st);
692}
693
694/***************************************************************************/
695
696struct shutdown_info
697{
698    unsigned32      secs;
699};
700
701static void *shutdown_thread
702(
703    void *p_
704)
705{
706    struct shutdown_info *p = (struct shutdown_info *) p_;
707    unsigned32          st;
708
709    printf ("+ Shutdown thread...\n");
710
711    printf ("  sleeping for %lu seconds\n", p->secs);
712    SLEEP (p->secs);
713
714    if (use_reserved_threads)
715    {
716        printf ("  unreserving threads (non blocking)...\n");
717        teardown_thread_pools(false /* don't block */);
718    }
719
720    printf ("  calling \"rpc_mgmt_stop_server_listening\"...\n");
721    rpc_mgmt_stop_server_listening (NULL, &st);
722
723    free (p);
724    printf ("  exiting thread\n");
725
726    return NULL;
727}
728
729void perf_shutdown2
730(
731    handle_t                h __attribute__(unused),
732    unsigned32              secs
733)
734{
735    struct shutdown_info *p;
736    pthread_t           thread;
737
738    common();
739
740    printf ("+ Creating shutdown thread\n");
741
742    p = (struct shutdown_info *) malloc (sizeof *p);
743    p->secs = secs;
744
745    pthread_create (&thread, pthread_attr_default,
746	shutdown_thread, (void *) p);
747    pthread_detach (&thread);
748}
749
750
751/***************************************************************************/
752
753void perf_call_callback
754(
755    handle_t                h,
756    unsigned32           idem
757)
758{
759    unsigned                     i;
760    unsigned32           c, passes;
761    unsigned32          st;
762
763    print_binding_info ("perf_call_callback", h);
764    common();
765
766    perfc_init(h, &passes);
767
768    for (i = 1; i <= passes; i++)
769    {
770        if (idem)
771        {
772            perfc_cb_idem(h, &c);
773        }
774        else
775        {
776            perfc_cb(h, &c);
777        }
778    }
779
780    if ((! idem) && c != passes)
781    {
782        printf("    ...count mismatch [%lu, %lu]\n", c, passes);
783        st = 1;
784#ifdef NOTDEF
785        pfm_$signal(st);
786#endif
787    }
788}
789
790/***************************************************************************/
791
792struct context
793{
794    unsigned long   magic;
795    unsigned long   data;
796};
797
798#define CONTEXT_MAGIC 0xfeedf00d
799
800void perf_context_t_rundown
801(
802    rpc_ss_context_t        context
803)
804{
805    struct context *p = (struct context *) context;
806
807    printf("+ In context rundown function\n");
808
809    if (p->magic != CONTEXT_MAGIC)
810    {
811        fprintf(stderr, "*** context mismatch; %08lx != %08x\n", p->magic, CONTEXT_MAGIC);
812        return;
813    }
814
815    free(context);
816}
817
818/***************************************************************************/
819
820void perf_get_context
821(
822    handle_t                h,
823    unsigned32           data,
824    perf_context_t          *context
825)
826{
827    struct context *p;
828
829    print_binding_info ("perf_get_context", h);
830    p = (struct context *) malloc(sizeof(struct context));
831
832    p->magic = CONTEXT_MAGIC;
833    p->data  = data;
834
835    *context = (perf_context_t) p;
836}
837
838/***************************************************************************/
839
840idl_boolean perf_test_context
841(
842    perf_context_t          context,
843    unsigned32           *data
844)
845{
846    struct context *p = (struct context *) context;
847
848    if (p->magic != CONTEXT_MAGIC)
849    {
850        fprintf(stderr, "*** context mismatch; %08lx != %08x\n", p->magic, CONTEXT_MAGIC);
851        return (false);
852    }
853
854    *data = p->data;
855
856    return (true);
857}
858
859/***************************************************************************/
860
861idl_boolean perf_free_context
862(
863    perf_context_t          *context,
864    unsigned32           *data
865)
866{
867    struct context *p = (struct context *) *context;
868
869    *context = NULL;
870
871    if (p->magic != CONTEXT_MAGIC)
872    {
873        fprintf(stderr, "*** context mismatch; %08lx != %08x\n", p->magic, CONTEXT_MAGIC);
874        return (false);
875    }
876
877    *data = p->data;
878
879    free(p);
880
881    return (true);
882}
883
884/***************************************************************************/
885
886void perf_brd_fault
887(
888    handle_t                h
889)
890{
891    common();
892    n_brd++;
893    print_binding_info ("perf_brd_fault", h);
894    RAISE (rpc_x_unknown_remote_fault);
895}
896
897
898/***************************************************************************/
899
900perf_v2_0_epv_t perf_epv =
901{
902    perf_init,
903    perf_info,
904    perf_null,
905    perf_null_idem,
906    perf_in,
907    perf_in_idem,
908    perf_out,
909    perf_out_idem,
910    perf_brd,
911    perf_maybe,
912    perf_brd_maybe,
913    perf_fp_test,
914    perf_register_b,
915    perf_unregister_b,
916    perf_exception,
917    perf_null_slow,
918    perf_null_slow_idem,
919    perf_shutdown,
920    perf_call_callback,
921    perf_get_context,
922    perf_test_context,
923    perf_free_context,
924    perf_shutdown2,
925    perf_brd_fault
926};
927