|
PAPI
5.3.0.0
|
00001 /****************************/ 00002 /* THIS IS OPEN SOURCE CODE */ 00003 /****************************/ 00004 00020 #include "linux-IOunit.h" 00021 00022 /* Declare our vector in advance */ 00023 papi_vector_t _IOunit_vector; 00024 00025 /* prototypes */ 00026 void user_signal_handler_IOUNIT( int hEvtSet, uint64_t address, uint64_t ovfVector, const ucontext_t *pContext ); 00027 00028 /***************************************************************************** 00029 ******************* BEGIN PAPI's COMPONENT REQUIRED FUNCTIONS ************* 00030 *****************************************************************************/ 00031 00032 /* 00033 * This is called whenever a thread is initialized 00034 */ 00035 int 00036 IOUNIT_init_thread( hwd_context_t * ctx ) 00037 { 00038 #ifdef DEBUG_BGQ 00039 printf( "IOUNIT_init_thread\n" ); 00040 #endif 00041 00042 ( void ) ctx; 00043 return PAPI_OK; 00044 } 00045 00046 00047 /* Initialize hardware counters, setup the function vector table 00048 * and get hardware information, this routine is called when the 00049 * PAPI process is initialized (IE PAPI_library_init) 00050 */ 00051 int 00052 IOUNIT_init_component( int cidx ) 00053 { 00054 #ifdef DEBUG_BGQ 00055 printf( "IOUNIT_init_component\n" ); 00056 #endif 00057 00058 _IOunit_vector.cmp_info.CmpIdx = cidx; 00059 #ifdef DEBUG_BGQ 00060 printf( "IOUNIT_init_component cidx = %d\n", cidx ); 00061 #endif 00062 00063 return ( PAPI_OK ); 00064 } 00065 00066 00067 /* 00068 * Control of counters (Reading/Writing/Starting/Stopping/Setup) 00069 * functions 00070 */ 00071 int 00072 IOUNIT_init_control_state( hwd_control_state_t * ptr ) 00073 { 00074 #ifdef DEBUG_BGQ 00075 printf( "IOUNIT_init_control_state\n" ); 00076 #endif 00077 int retval; 00078 00079 IOUNIT_control_state_t * this_state = ( IOUNIT_control_state_t * ) ptr; 00080 00081 this_state->EventGroup = Bgpm_CreateEventSet(); 00082 retval = _check_BGPM_error( this_state->EventGroup, "Bgpm_CreateEventSet" ); 00083 if ( retval < 0 ) return retval; 00084 00085 // initialize overflow flag to OFF (0) 00086 this_state->overflow = 0; 00087 this_state->overflow_count = 0; 00088 00089 return PAPI_OK; 00090 } 00091 00092 00093 /* 00094 * 00095 */ 00096 int 00097 IOUNIT_start( hwd_context_t * ctx, hwd_control_state_t * ptr ) 00098 { 00099 #ifdef DEBUG_BGQ 00100 printf( "IOUNIT_start\n" ); 00101 #endif 00102 ( void ) ctx; 00103 int retval; 00104 IOUNIT_control_state_t * this_state = ( IOUNIT_control_state_t * ) ptr; 00105 00106 retval = Bgpm_ResetStart( this_state->EventGroup ); 00107 retval = _check_BGPM_error( retval, "Bgpm_ResetStart" ); 00108 if ( retval < 0 ) return retval; 00109 00110 return ( PAPI_OK ); 00111 } 00112 00113 00114 /* 00115 * 00116 */ 00117 int 00118 IOUNIT_stop( hwd_context_t * ctx, hwd_control_state_t * ptr ) 00119 { 00120 #ifdef DEBUG_BGQ 00121 printf( "IOUNIT_stop\n" ); 00122 #endif 00123 ( void ) ctx; 00124 int retval; 00125 IOUNIT_control_state_t * this_state = ( IOUNIT_control_state_t * ) ptr; 00126 00127 retval = Bgpm_Stop( this_state->EventGroup ); 00128 retval = _check_BGPM_error( retval, "Bgpm_Stop" ); 00129 if ( retval < 0 ) return retval; 00130 00131 return ( PAPI_OK ); 00132 } 00133 00134 00135 /* 00136 * 00137 */ 00138 int 00139 IOUNIT_read( hwd_context_t * ctx, hwd_control_state_t * ptr, 00140 long_long ** events, int flags ) 00141 { 00142 #ifdef DEBUG_BGQ 00143 printf( "IOUNIT_read\n" ); 00144 #endif 00145 ( void ) ctx; 00146 ( void ) flags; 00147 int i, numEvts; 00148 IOUNIT_control_state_t * this_state = ( IOUNIT_control_state_t * ) ptr; 00149 00150 numEvts = Bgpm_NumEvents( this_state->EventGroup ); 00151 if ( numEvts == 0 ) { 00152 #ifdef DEBUG_BGPM 00153 printf ("Error: ret value is %d for BGPM API function Bgpm_NumEvents.\n", numEvts ); 00154 #endif 00155 //return ( EXIT_FAILURE ); 00156 } 00157 00158 for ( i = 0; i < numEvts; i++ ) 00159 this_state->counts[i] = _common_getEventValue( i, this_state->EventGroup ); 00160 00161 *events = this_state->counts; 00162 00163 return ( PAPI_OK ); 00164 } 00165 00166 00167 /* 00168 * 00169 */ 00170 int 00171 IOUNIT_shutdown_thread( hwd_context_t * ctx ) 00172 { 00173 #ifdef DEBUG_BGQ 00174 printf( "IOUNIT_shutdown_thread\n" ); 00175 #endif 00176 00177 ( void ) ctx; 00178 return ( PAPI_OK ); 00179 } 00180 00181 00182 /* 00183 * user_signal_handler 00184 * 00185 * This function is used when hardware overflows are working or when 00186 * software overflows are forced 00187 */ 00188 void 00189 user_signal_handler_IOUNIT( int hEvtSet, uint64_t address, uint64_t ovfVector, const ucontext_t *pContext ) 00190 { 00191 #ifdef DEBUG_BGQ 00192 printf( "user_signal_handler_IOUNIT\n" ); 00193 #endif 00194 ( void ) address; 00195 int retval; 00196 unsigned i; 00197 int isHardware = 1; 00198 int cidx = _IOunit_vector.cmp_info.CmpIdx; 00199 long_long overflow_bit = 0; 00200 caddr_t address1; 00201 _papi_hwi_context_t ctx; 00202 ctx.ucontext = ( hwd_ucontext_t * ) pContext; 00203 ThreadInfo_t *thread = _papi_hwi_lookup_thread( 0 ); 00204 EventSetInfo_t *ESI; 00205 ESI = thread->running_eventset[cidx]; 00206 // Get the indices of all events which have overflowed. 00207 unsigned ovfIdxs[BGPM_MAX_OVERFLOW_EVENTS]; 00208 unsigned len = BGPM_MAX_OVERFLOW_EVENTS; 00209 00210 retval = Bgpm_GetOverflowEventIndices( hEvtSet, ovfVector, ovfIdxs, &len ); 00211 if ( retval < 0 ) { 00212 #ifdef DEBUG_BGPM 00213 printf ( "Error: ret value is %d for BGPM API function Bgpm_GetOverflowEventIndices.\n", 00214 retval ); 00215 #endif 00216 return; 00217 } 00218 00219 if ( thread == NULL ) { 00220 PAPIERROR( "thread == NULL in user_signal_handler!" ); 00221 return; 00222 } 00223 00224 if ( ESI == NULL ) { 00225 PAPIERROR( "ESI == NULL in user_signal_handler!"); 00226 return; 00227 } 00228 00229 if ( ESI->overflow.flags == 0 ) { 00230 PAPIERROR( "ESI->overflow.flags == 0 in user_signal_handler!"); 00231 return; 00232 } 00233 00234 for ( i = 0; i < len; i++ ) { 00235 uint64_t hProf; 00236 Bgpm_GetEventUser1( hEvtSet, ovfIdxs[i], &hProf ); 00237 if ( hProf ) { 00238 overflow_bit ^= 1 << ovfIdxs[i]; 00239 break; 00240 } 00241 00242 } 00243 00244 if ( ESI->overflow.flags & PAPI_OVERFLOW_FORCE_SW ) { 00245 #ifdef DEBUG_BGQ 00246 printf("OVERFLOW_SOFTWARE\n"); 00247 #endif 00248 address1 = GET_OVERFLOW_ADDRESS( ctx ); 00249 _papi_hwi_dispatch_overflow_signal( ( void * ) &ctx, address1, NULL, 0, 0, &thread, cidx ); 00250 return; 00251 } 00252 else if ( ESI->overflow.flags & PAPI_OVERFLOW_HARDWARE ) { 00253 #ifdef DEBUG_BGQ 00254 printf("OVERFLOW_HARDWARE\n"); 00255 #endif 00256 address1 = GET_OVERFLOW_ADDRESS( ctx ); 00257 _papi_hwi_dispatch_overflow_signal( ( void * ) &ctx, address1, &isHardware, overflow_bit, 0, &thread, cidx ); 00258 } 00259 else { 00260 #ifdef DEBUG_BGQ 00261 printf("OVERFLOW_NONE\n"); 00262 #endif 00263 PAPIERROR( "ESI->overflow.flags is set to something other than PAPI_OVERFLOW_HARDWARE or PAPI_OVERFLOW_FORCE_SW (%#x)", thread->running_eventset[cidx]->overflow.flags); 00264 } 00265 } 00266 00267 00268 /* 00269 * Set Overflow 00270 * 00271 * This is commented out in BG/L/P - need to explore and complete... 00272 * However, with true 64-bit counters in BG/Q and all counters for PAPI 00273 * always starting from a true zero (we don't allow write...), the possibility 00274 * for overflow is remote at best... 00275 */ 00276 int 00277 IOUNIT_set_overflow( EventSetInfo_t * ESI, int EventIndex, int threshold ) 00278 { 00279 #ifdef DEBUG_BGQ 00280 printf("BEGIN IOUNIT_set_overflow\n"); 00281 #endif 00282 IOUNIT_control_state_t * this_state = ( IOUNIT_control_state_t * ) ESI->ctl_state; 00283 int retval; 00284 int evt_idx; 00285 00286 evt_idx = ESI->EventInfoArray[EventIndex].pos[0]; 00287 SUBDBG( "Hardware counter %d (vs %d) used in overflow, threshold %d\n", 00288 evt_idx, EventIndex, threshold ); 00289 #ifdef DEBUG_BGQ 00290 printf( "Hardware counter %d (vs %d) used in overflow, threshold %d\n", 00291 evt_idx, EventIndex, threshold ); 00292 #endif 00293 /* If this counter isn't set to overflow, it's an error */ 00294 if ( threshold == 0 ) { 00295 /* Remove the signal handler */ 00296 retval = _papi_hwi_stop_signal( _IOunit_vector.cmp_info.hardware_intr_sig ); 00297 if ( retval != PAPI_OK ) 00298 return ( retval ); 00299 } 00300 else { 00301 this_state->overflow = 1; 00302 this_state->overflow_count++; 00303 this_state->overflow_list[this_state->overflow_count-1].threshold = threshold; 00304 this_state->overflow_list[this_state->overflow_count-1].EventIndex = evt_idx; 00305 00306 #ifdef DEBUG_BGQ 00307 printf( "IOUNIT_set_overflow: Enable the signal handler\n" ); 00308 #endif 00309 /* Enable the signal handler */ 00310 retval = _papi_hwi_start_signal( _IOunit_vector.cmp_info.hardware_intr_sig, 00311 NEED_CONTEXT, 00312 _IOunit_vector.cmp_info.CmpIdx ); 00313 if ( retval != PAPI_OK ) 00314 return ( retval ); 00315 00316 retval = _common_set_overflow_BGPM( this_state->EventGroup, 00317 this_state->overflow_list[this_state->overflow_count-1].EventIndex, 00318 this_state->overflow_list[this_state->overflow_count-1].threshold, 00319 user_signal_handler_IOUNIT ); 00320 if ( retval < 0 ) return retval; 00321 } 00322 00323 return ( PAPI_OK ); 00324 } 00325 00326 00327 /* This function sets various options in the component 00328 * The valid codes being passed in are PAPI_SET_DEFDOM, 00329 * PAPI_SET_DOMAIN, PAPI_SETDEFGRN, PAPI_SET_GRANUL * and PAPI_SET_INHERIT 00330 */ 00331 int 00332 IOUNIT_ctl( hwd_context_t * ctx, int code, _papi_int_option_t * option ) 00333 { 00334 #ifdef DEBUG_BGQ 00335 printf( "IOUNIT_ctl\n" ); 00336 #endif 00337 00338 ( void ) ctx; 00339 ( void ) code; 00340 ( void ) option; 00341 return ( PAPI_OK ); 00342 } 00343 00344 00345 /* 00346 * 00347 */ 00348 int 00349 IOUNIT_update_control_state( hwd_control_state_t * ptr, 00350 NativeInfo_t * native, int count, 00351 hwd_context_t * ctx ) 00352 { 00353 #ifdef DEBUG_BGQ 00354 printf( "IOUNIT_update_control_state: count = %d\n", count ); 00355 #endif 00356 ( void ) ctx; 00357 int retval, index, i, k; 00358 IOUNIT_control_state_t * this_state = ( IOUNIT_control_state_t * ) ptr; 00359 00360 // Delete and re-create BGPM eventset 00361 retval = _common_deleteRecreate( &this_state->EventGroup ); 00362 if ( retval < 0 ) return retval; 00363 00364 #ifdef DEBUG_BGQ 00365 printf( "IOUNIT_update_control_state: EventGroup=%d, overflow = %d\n", 00366 this_state->EventGroup, this_state->overflow ); 00367 #endif 00368 00369 // otherwise, add the events to the eventset 00370 for ( i = 0; i < count; i++ ) { 00371 index = ( native[i].ni_event ) + OFFSET; 00372 00373 native[i].ni_position = i; 00374 00375 #ifdef DEBUG_BGQ 00376 printf("IOUNIT_update_control_state: ADD event: i = %d, index = %d\n", i, index ); 00377 #endif 00378 00379 /* Add events to the BGPM eventGroup */ 00380 retval = Bgpm_AddEvent( this_state->EventGroup, index ); 00381 retval = _check_BGPM_error( retval, "Bgpm_AddEvent" ); 00382 if ( retval < 0 ) return retval; 00383 } 00384 00385 // since update_control_state trashes overflow settings, this puts things 00386 // back into balance for BGPM 00387 if ( 1 == this_state->overflow ) { 00388 for ( k = 0; k < this_state->overflow_count; k++ ) { 00389 retval = _common_set_overflow_BGPM( this_state->EventGroup, 00390 this_state->overflow_list[k].EventIndex, 00391 this_state->overflow_list[k].threshold, 00392 user_signal_handler_IOUNIT ); 00393 if ( retval < 0 ) return retval; 00394 } 00395 } 00396 00397 return ( PAPI_OK ); 00398 } 00399 00400 00401 /* 00402 * This function has to set the bits needed to count different domains 00403 * In particular: PAPI_DOM_USER, PAPI_DOM_KERNEL PAPI_DOM_OTHER 00404 * By default return PAPI_EINVAL if none of those are specified 00405 * and PAPI_OK with success 00406 * PAPI_DOM_USER is only user context is counted 00407 * PAPI_DOM_KERNEL is only the Kernel/OS context is counted 00408 * PAPI_DOM_OTHER is Exception/transient mode (like user TLB misses) 00409 * PAPI_DOM_ALL is all of the domains 00410 */ 00411 int 00412 IOUNIT_set_domain( hwd_control_state_t * cntrl, int domain ) 00413 { 00414 #ifdef DEBUG_BGQ 00415 printf( "IOUNIT_set_domain\n" ); 00416 #endif 00417 int found = 0; 00418 ( void ) cntrl; 00419 00420 if ( PAPI_DOM_USER & domain ) 00421 found = 1; 00422 00423 if ( PAPI_DOM_KERNEL & domain ) 00424 found = 1; 00425 00426 if ( PAPI_DOM_OTHER & domain ) 00427 found = 1; 00428 00429 if ( !found ) 00430 return ( PAPI_EINVAL ); 00431 00432 return ( PAPI_OK ); 00433 } 00434 00435 00436 /* 00437 * 00438 */ 00439 int 00440 IOUNIT_reset( hwd_context_t * ctx, hwd_control_state_t * ptr ) 00441 { 00442 #ifdef DEBUG_BGQ 00443 printf( "IOUNIT_reset\n" ); 00444 #endif 00445 ( void ) ctx; 00446 int retval; 00447 IOUNIT_control_state_t * this_state = ( IOUNIT_control_state_t * ) ptr; 00448 00449 /* we can't simply call Bgpm_Reset() since PAPI doesn't have the 00450 restriction that an EventSet has to be stopped before resetting is 00451 possible. However, BGPM does have this restriction. 00452 Hence we need to stop, reset and start */ 00453 retval = Bgpm_Stop( this_state->EventGroup ); 00454 retval = _check_BGPM_error( retval, "Bgpm_Stop" ); 00455 if ( retval < 0 ) return retval; 00456 00457 retval = Bgpm_ResetStart( this_state->EventGroup ); 00458 retval = _check_BGPM_error( retval, "Bgpm_ResetStart" ); 00459 if ( retval < 0 ) return retval; 00460 00461 return ( PAPI_OK ); 00462 } 00463 00464 00465 /* 00466 * PAPI Cleanup Eventset 00467 * 00468 * Destroy and re-create the BGPM / IOunit EventSet 00469 */ 00470 int 00471 IOUNIT_cleanup_eventset( hwd_control_state_t * ctrl ) 00472 { 00473 #ifdef DEBUG_BGQ 00474 printf( "IOUNIT_cleanup_eventset\n" ); 00475 #endif 00476 int retval; 00477 00478 IOUNIT_control_state_t * this_state = ( IOUNIT_control_state_t * ) ctrl; 00479 00480 // create a new empty bgpm eventset 00481 // reason: bgpm doesn't permit to remove events from an eventset; 00482 // hence we delete the old eventset and create a new one 00483 retval = _common_deleteRecreate( &this_state->EventGroup ); // HJ try to use delete() only 00484 if ( retval < 0 ) return retval; 00485 00486 // set overflow flag to OFF (0) 00487 this_state->overflow = 0; 00488 this_state->overflow_count = 0; 00489 00490 return ( PAPI_OK ); 00491 } 00492 00493 00494 /* 00495 * Native Event functions 00496 */ 00497 int 00498 IOUNIT_ntv_enum_events( unsigned int *EventCode, int modifier ) 00499 { 00500 #ifdef DEBUG_BGQ 00501 //printf( "IOUNIT_ntv_enum_events\n" ); 00502 #endif 00503 00504 switch ( modifier ) { 00505 case PAPI_ENUM_FIRST: 00506 *EventCode = 0; 00507 00508 return ( PAPI_OK ); 00509 break; 00510 00511 case PAPI_ENUM_EVENTS: 00512 { 00513 int index = ( *EventCode ) + OFFSET; 00514 00515 if ( index < IOUNIT_MAX_COUNTERS ) { 00516 *EventCode = *EventCode + 1; 00517 return ( PAPI_OK ); 00518 } else 00519 return ( PAPI_ENOEVNT ); 00520 00521 break; 00522 } 00523 default: 00524 return ( PAPI_EINVAL ); 00525 } 00526 return ( PAPI_EINVAL ); 00527 } 00528 00529 00530 /* 00531 * 00532 */ 00533 int 00534 IOUNIT_ntv_name_to_code( char *name, unsigned int *event_code ) 00535 { 00536 #ifdef DEBUG_BGQ 00537 printf( "IOUNIT_ntv_name_to_code\n" ); 00538 #endif 00539 int ret; 00540 00541 /* Return event id matching a given event label string */ 00542 ret = Bgpm_GetEventIdFromLabel ( name ); 00543 00544 if ( ret <= 0 ) { 00545 #ifdef DEBUG_BGPM 00546 printf ("Error: ret value is %d for BGPM API function '%s'.\n", 00547 ret, "Bgpm_GetEventIdFromLabel" ); 00548 #endif 00549 return PAPI_ENOEVNT; 00550 } 00551 else if ( ret < OFFSET || ret > IOUNIT_MAX_COUNTERS ) // not an IOUnit event 00552 return PAPI_ENOEVNT; 00553 else 00554 *event_code = ( ret - OFFSET ) ; 00555 00556 return PAPI_OK; 00557 } 00558 00559 00560 /* 00561 * 00562 */ 00563 int 00564 IOUNIT_ntv_code_to_name( unsigned int EventCode, char *name, int len ) 00565 { 00566 #ifdef DEBUG_BGQ 00567 //printf( "IOUNIT_ntv_code_to_name\n" ); 00568 #endif 00569 int index; 00570 00571 index = ( EventCode ) + OFFSET; 00572 00573 if ( index >= MAX_COUNTERS ) 00574 return PAPI_ENOEVNT; 00575 00576 strncpy( name, Bgpm_GetEventIdLabel( index ), len ); 00577 00578 if ( name == NULL ) { 00579 #ifdef DEBUG_BGPM 00580 printf ("Error: ret value is NULL for BGPM API function Bgpm_GetEventIdLabel.\n" ); 00581 #endif 00582 return PAPI_ENOEVNT; 00583 } 00584 00585 return ( PAPI_OK ); 00586 } 00587 00588 00589 /* 00590 * 00591 */ 00592 int 00593 IOUNIT_ntv_code_to_descr( unsigned int EventCode, char *name, int len ) 00594 { 00595 #ifdef DEBUG_BGQ 00596 //printf( "IOUNIT_ntv_code_to_descr\n" ); 00597 #endif 00598 int retval, index; 00599 00600 index = ( EventCode ) + OFFSET; 00601 00602 retval = Bgpm_GetLongDesc( index, name, &len ); 00603 retval = _check_BGPM_error( retval, "Bgpm_GetLongDesc" ); 00604 if ( retval < 0 ) return retval; 00605 00606 return ( PAPI_OK ); 00607 } 00608 00609 00610 /* 00611 * 00612 */ 00613 int 00614 IOUNIT_ntv_code_to_bits( unsigned int EventCode, hwd_register_t * bits ) 00615 { 00616 #ifdef DEBUG_BGQ 00617 printf( "IOUNIT_ntv_code_to_bits\n" ); 00618 #endif 00619 ( void ) EventCode; 00620 ( void ) bits; 00621 return ( PAPI_OK ); 00622 } 00623 00624 00625 /* 00626 * 00627 */ 00628 papi_vector_t _IOunit_vector = { 00629 .cmp_info = { 00630 /* default component information (unspecified values are initialized to 0) */ 00631 .name = "bgpm/IOUnit", 00632 .short_name = "IOUnit", 00633 .description = "Blue Gene/Q IOUnit component", 00634 .num_cntrs = IOUNIT_MAX_COUNTERS, 00635 .num_mpx_cntrs = IOUNIT_MAX_COUNTERS, 00636 .default_domain = PAPI_DOM_USER, 00637 .available_domains = PAPI_DOM_USER | PAPI_DOM_KERNEL, 00638 .default_granularity = PAPI_GRN_THR, 00639 .available_granularities = PAPI_GRN_THR, 00640 00641 .hardware_intr_sig = PAPI_INT_SIGNAL, 00642 .hardware_intr = 1, 00643 00644 .kernel_multiplex = 0, 00645 00646 /* component specific cmp_info initializations */ 00647 .fast_real_timer = 0, 00648 .fast_virtual_timer = 0, 00649 .attach = 0, 00650 .attach_must_ptrace = 0, 00651 } 00652 , 00653 00654 /* sizes of framework-opaque component-private structures */ 00655 .size = { 00656 .context = sizeof ( IOUNIT_context_t ), 00657 .control_state = sizeof ( IOUNIT_control_state_t ), 00658 .reg_value = sizeof ( IOUNIT_register_t ), 00659 .reg_alloc = sizeof ( IOUNIT_reg_alloc_t ), 00660 } 00661 , 00662 /* function pointers in this component */ 00663 .init_thread = IOUNIT_init_thread, 00664 .init_component = IOUNIT_init_component, 00665 .init_control_state = IOUNIT_init_control_state, 00666 .start = IOUNIT_start, 00667 .stop = IOUNIT_stop, 00668 .read = IOUNIT_read, 00669 .shutdown_thread = IOUNIT_shutdown_thread, 00670 .set_overflow = IOUNIT_set_overflow, 00671 .cleanup_eventset = IOUNIT_cleanup_eventset, 00672 .ctl = IOUNIT_ctl, 00673 00674 .update_control_state = IOUNIT_update_control_state, 00675 .set_domain = IOUNIT_set_domain, 00676 .reset = IOUNIT_reset, 00677 00678 .ntv_name_to_code = IOUNIT_ntv_name_to_code, 00679 .ntv_enum_events = IOUNIT_ntv_enum_events, 00680 .ntv_code_to_name = IOUNIT_ntv_code_to_name, 00681 .ntv_code_to_descr = IOUNIT_ntv_code_to_descr, 00682 .ntv_code_to_bits = IOUNIT_ntv_code_to_bits 00683 };