SPARC: Rendimiento del SPARC64 VI

En un post anterior, hemos hablado cómo podemos medir el rendimiento del procesador UltraSPARC T2+. Siguiendo con esta serie de posts, ahora vamos a ver como podemos analizar el comportamiento del procesador SPARC64 VI, en el link anterior podemos ver algunas de las características de este procesador. Podemos destacar, que se trata de un procesador dual-core, con 2 threads hardware por core.

Antes de continuar y tal como comentamos en el post sobre UltraSPARC T2+, es muy recomendable visitar el blog de Ravindra Talashikar.

Es procesdor SPARC64 VI implementa los threads hardware mediante VMT (Vertical Multi-thread), por lo que solo un thread está activo a la vez en un core. Es importante conocer la implementación VMT de este tipo de procesadores, ya que esto nos ayudará a medir el rendimiento del procesador.

Tal como hemos dicho un core gestiona 2 threads hardware, pero solo uno está activo a la vez, esto significa que un procesador cuya velocidad es de 2.1MHz, cada core puede llegar a ajecutar como máximo:

2.1 x 1000 x 1000 = Número máximo de instrucciones por segundo.

En el documento sobre Extensiones de SPARC64 VI podemos encontrar información sobre los distintos contadores disponibles en el procesador, página 212 Multi-thread specific Event Counters. Nos interesan especialmente:

  • active_cycle_count, ciclos asignados al thread hardware.
  • active_thread_syspend, número de ciclos cuando ambos threads de un core no están ejecutando instrucciones.

Con estos dos contadores, podemos construir una sencilla formula que nos indique el rendimiento del procesador, por la propia naturaleza el SPARC64 VI, los threads no podemos tratarlos de forma separado como hacíamos en el UltraSPARC T2+. Ahora tendremos que analizar el core en su conjunto y no cada thread por separado. Podríamos decir que el rendimeinto de un core sería igual a la suma de los ciclos asignados a los dos threads (active_cycle_count) menos la suma de los contadores active_thread_syspend de los dos threads de un core,

Para un thread el porcentaje de uso sería:

((active_cycle_count – active_thread_syspend) x 100 ) / La mitad del número max de instrucciones por core

Para medir el porcentaje de uso de un core, solo tenemos que sumar el porcentaje de los 2 threads y dividimos entre 2. Un thread hardware de un core, puede ejecutar el solo como máximo el número máximo de instrucciones por segundo, siempre y cuando el otro thread de ese mismo core no ejecute ninguna instrucción. Si los dos threads de un core están al 100% cada uno solo ejecutará la mitad de las instrucciones máximas que puede ejecutar un core.

cpustat

El comando cpustat nos permite consultar una serie de contadores hardware disponible en los distintos procesadores. Cada procesador tiene sus propios contadores, por lo que es importante, que antes de utilizar el comando cpustat comprobemos cuales son los contadores disponibles en los procesadores de la máquina.

root@host # cpustat -h
Usage:
        cpustat [-c events] [-p period] [-nstD] [interval [count]]

        -c events specify processor events to be monitored
        -n        suppress titles
        -p period cycle through event list periodically
        -s        run user soaker thread for system-only events
        -t        include %tick register
        -D        enable debug mode
        -h        print extended usage information

        Use cputrack(1) to monitor per-process statistics.

        CPU performance counter interface: SPARC64 VI & VII

        event specification syntax:
        [picn=][,attr[n][=]][,[picn=][,attr[n][=]],...]

        event0:  cycle_counts instruction_counts only_this_thread_active
                 w_cse_window_empty w_op_stv_wait_nc_pend op_stv_wait
                 load_store_instructions branch_instructions
                 floating_instructions impdep2_instructions
                 prefetch_instructions flush_rs 2iid_use toq_rsbr_phantom
                 trap_int_vector ts_by_sxmiss both_threads_active
                 active_cycle_count op_stv_wait_sxmiss eu_comp_wait
                 op_l1_thrashing swpf_fail_all sx_miss_wait_pf
                 jbus_cpi_count jbus_reqbus1_busy

        event1:  cycle_counts instruction_counts instruction_flow_counts
                 iwr_empty op_stv_wait load_store_instructions
                 branch_instructions floating_instructions
                 impdep2_instructions prefetch_instructions rs1 1iid_use
                 trap_all thread_switch_all only_this_thread_active
                 active_cycle_count act_thread_suspend cse_window_empty
                 inh_cmit_gpr_2write if_l1_thrashing swpf_success_all
                 sx_miss_wait_dm jbus_bi_count lost_softpf_pfp_full
                 jbus_reqbus0_busy

        event2:  cycle_counts instruction_counts single_mode_instructions
                 w_branch_comp_wait w_op_stv_wait_sxmiss_ex op_stv_wait
                 load_store_instructions branch_instructions
                 floating_instructions impdep2_instructions
                 prefetch_instructions 4iid_use flush_rs trap_spill
                 ts_by_timer active_cycle_count 0iid_use
                 op_stv_wait_nc_pend 0endop write_op_uTLB sx_miss_count_pf
                 jbus_cpd_count snres_64 jbus_reqbus3_busy

        event3:  cycle_counts instruction_counts single_mode_cycle_counts
                 w_eu_comp_wait w_op_stv_wait_sxmiss op_stv_wait
                 load_store_instructions branch_instructions
                 floating_instructions impdep2_instructions
                 prefetch_instructions 3iid_use trap_int_level
                 ts_by_data_arrive both_threads_empty active_cycle_count
                 op_stv_wait_nc_pend op_stv_wait_sxmiss_ex branch_comp_wait
                 write_if_uTLB sx_miss_count_dm jbus_cpb_count snres_256
                 lost_softpf_by_abort jbus_reqbus2_busy

        event4:  cycle_counts instruction_counts d_move_wait w_op_stv_wait
                 w_fl_comp_wait op_stv_wait load_store_instructions
                 branch_instructions floating_instructions
                 impdep2_instructions prefetch_instructions sync_intlk
                 trap_trap_inst ts_by_if active_cycle_count fl_comp_wait
                 op_r_iu_req_mi_go sx_read_count_pf jbus_odrbus_busy
                 sx_miss_count_dm_if jbus_odrbus1_busy

        event5:  cycle_counts instruction_counts instruction_flow_counts
                 iwr_empty op_stv_wait load_store_instructions
                 branch_instructions floating_instructions
                 impdep2_instructions prefetch_instructions trap_fill
                 ts_by_intr active_cycle_count flush_rs
                 cse_window_empty_sp_full op_stv_wait_ex 3endop
                 if_r_iu_req_mi_go swpf_lbs_hit sx_read_count_dm
                 jbus_reqbus_busy sx_btc_count jbus_odrbus0_busy

        event6:  cycle_counts instruction_counts xma_inst w_0endop
                 w_op_stv_wait_ex op_stv_wait load_store_instructions
                 branch_instructions floating_instructions
                 impdep2_instructions prefetch_instructions trap_DMMU_miss
                 ts_by_suspend ts_by_other active_cycle_count decall_intlk
                 2endop op_stv_wait_sxmiss op_wait_all dvp_count_pf
                 sx_miss_count_dm_opex jbus_odrbus3_busy

        event7:  cycle_counts instruction_counts cse_priority_wait w_d_move
                 w_cse_window_empty_sp_full op_stv_wait
                 load_store_instructions branch_instructions
                 floating_instructions impdep2_instructions
                 prefetch_instructions regwin_intlk rs1 trap_IMMU_miss
                 active_cycle_count both_threads_suspended 1endop
                 op_stv_wait_sxmiss_ex if_wait_all dvp_count_dm
                 sx_miss_count_dm_opsh jbus_odrbus2_busy

        attributes: nouser sys

        See the "SPARC64 VI extensions" and "SPARC64 VII extensions" for
        descriptions of these events.

De todos los contadores disponibles en el comando cpustat que pueden ser utilizados en los procesadores SPARC64 VI, nos van a interesar:

  • active_cycle_count
  • act_thread_suspend

Lo siguiente es un ejemplo de la ejecución del comando cpustat.

root@host # cpustat  -t -c pic1=act_thread_suspend,pic3=active_cycle_count,sys -c pic1=act_thread_suspend,pic3=active_cycle_count,sys 1
   time cpu event     %tick      pic1      pic3
  1.008 168  tick 2162570902 1282410437 1282897885  # pic1=act_thread_suspend,pic3= active_cycle_count,sys
  1.008 130  tick 2163776033 383279484 383610644  # pic1=act_thread_suspend,pic3= active_cycle_count,sys
  1.008   2  tick 2163553969 2120102957 2163565728  # pic1=act_thread_suspend,pic3= active_cycle_count,sys
  1.008 251  tick 2162549377 584650987 589144197  # pic1=act_thread_suspend,pic3= active_cycle_count,sys
  2.008 130  tick 2148270412 524002074 524131685  # pic1=act_thread_suspend,pic3= active_cycle_count,sys
  2.008 168  tick 2147864206 999846867 1000273984  # pic1=act_thread_suspend,pic3= active_cycle_count,sys
  2.008 251  tick 2148005062 1072662447 1072852410  # pic1=act_thread_suspend,pic3= active_cycle_count,sys
  2.008   2  tick 2147721610 2104781708 2147715688  # pic1=act_thread_suspend,pic3= active_cycle_count,sys
  3.008 130  tick 2148613915 861289690 861594122  # pic1=act_thread_suspend,pic3= active_cycle_count,sys
  3.008 251  tick 2148332352 715266764 715965383  # pic1=act_thread_suspend,pic3= active_cycle_count,sys
  3.008 168  tick 2148812218 916482914 917347117  # pic1=act_thread_suspend,pic3= active_cycle_count,sys
  3.008   2  tick 2148215534 2064217641 2116890140  # pic1=act_thread_suspend,pic3= active_cycle_count,sys
^C
root@host #

Según lo que hemos comentado antes, con esta salida podemos averiguar el porcentaje de uso de cada uno de los threads hardware de un core y por lo tanto el porcentaje de uso del core.

El core 1 está formado por los threads hardware 2 y 3, para nuestro ejemplo, solo tenemos que coger la salida del comando cpustat y mediante un script calcular el porcentaje de uso del thread hardware, para la línea:

2.008 2 tick 2147721610 2104781708 2147715688 # pic1=act_thread_suspend,pic3= active_cycle_count,sys

(( 2104781708 – 2147721610 ) x 100 ) / 1074161539 = % uso del thread 2

0 = % uso del thread 3, el cual no aparece en la salida del comando, porque no se está utilizando.

% uso del core = ( 3% + 0%) / 2

Hemos realizado una prueba, sometiendo a la máquina a un periodo de carga para comprobar como aumenta el % de uso del core que estamos analizando, la salida del comando cpustat

root@host #  cpustat  -t -c pic1=act_thread_suspend,pic3=active_cycle_count,sys -c pic1=act_thread_suspend,pic3=active_cycle_count,nouser,sys 1 | grep " 2 "
   time cpu event     %tick      pic1      pic3
  1.008 168  tick 2161961978 320334294 320712674  # pic1=act_thread_suspend,pic3=active_cycle_count,sys
  1.008 251  tick 2161813749 2082136079 2123271128  # pic1=act_thread_suspend,pic3=active_cycle_count,sys
...
 36.005   2  tick 2153397095  16036608 2120222175  # pic1=act_thread_suspend,pic3=active_cycle_count,nouser,sys
 37.002   2  tick 2143755997  16052492 2141377900  # pic1=act_thread_suspend,pic3=active_cycle_count,sys
 38.003   2  tick 2151078348      3255 2107581823  # pic1=act_thread_suspend,pic3=active_cycle_count,nouser,sys
 39.017   2  tick 2178950545  19339186 2176116566  # pic1=act_thread_suspend,pic3=active_cycle_count,sys
 40.024   2  tick 2163729641   6445891 2116117804  # pic1=act_thread_suspend,pic3=active_cycle_count,nouser,sys
 41.002   2  tick 2102064856  12838681 2099355234  # pic1=act_thread_suspend,pic3=active_cycle_count,sys
...

Para la línea:

40.024 2 tick 2163729641 6445891 2116117804 # pic1=act_thread_suspend,pic3=active_cycle_count,nouser,sys

Para el thread 2 del core el porcentaje de uso sería:

((2116117804 – 6445891 ) x 100 ) / 1074161539 = 196

Para el thread 3 del mismo core el porcentaj de uso es 0, ya que este thread lo hemos desactivado.

El porcentaje de uso del core = (196 + 0 ) / 2 = 98%

corestat

En el blog de Ravindra Talashikar podemos encontrar la utilidad corestat, que consiste en unos scripts en PERL, los cuales devuelven como salida el uso de los cores, threads hardware y pipelines de los distintos procesadores. Los scripts están preparados para calcular los porcentajes de los procesadores UltraSPARC T2+, SPARC64 VI y SPARC64 VII. A menos que te crees tus propios script para tratar la salida del comando cpustat es recomendable que los bajesmos y probemos la utilidad corestat