Fran Diéguez
frandieguez@gnome.org 2011-2020

# Que se está optimizando?

Ao optimizar GNOME o primeiro que hai que lembrar é isto: non se está tentando mellorar o programa, estase tentando mellorando facer que as persoas usen o equipo máis felices.

Programas mellores fan á xente máis feliz pero existen algunhas mellores que faranos máis felices que outras: tempo de resposta, tempo de inicio, facilidade para acceder a ordes e que o equipo non teña que usar a memoria de intercambio cando máis de dous programas estean abertos.

A optimización tradicional contempla conceptos como o uso de CPI, o tamaño do código, o número de pulsacións do reato e o uso de memoria de programa. Elixiuse esta segunda lista para correlar como a primeira, porén existe unha diferenza importante. Á persoa que usa GNOME non lle importa a segunda lista, pero sí a primeira. Ao optimizar os programas de GNOME reducirase o uso de CPU, o uso de memoria e todo aquelo, pero son conceptos para o fin, non o obxectivo final. Optimízase para as persoas.

# Realizar a optimización

Na sección anterior omitiuse un calificador importante: optimizar algo debe ser medíbel. Non se pode medir a felicidade. Porén pódese medir o tempo de inicio dun programa para saber se se mellorou. A felicidade do usuario aumentará pois.

Optimization is the process of measurement, refinement and re-measurement. So the first thing you must do is find a way to measure what you are optimizing. Ideally this measurement is a single number, for example: the time taken to perform a task. This is your benchmark, it is the only way to tell if you are winning or losing. There is a big difference between a program that should be fast and a program that is fast.

Unha vez que ten unha proba de rendemento básica debe atopar por que o seu código non o está facendo tan ben como debería. É tentado facelo inspeccionando: simplemente mirar o código e tratar de atopar algo que parece que precisa unha mellora. Estará perdendo o tempo, usar un perfilador para obter unha lista detallada do que o seu programa está facendo é, realmente, a única forma de estar seguro.

Xeralmente o problema está illado en pequenas partes do código. Elixa a peor parte e concéntrese nesa primeiro. Unha vez que o teña feito, volva ao perfilador e repita o proceso. Segundo proceda, as melloras obtidas en cada paso faranse cada vez máis pequenas, nalgún punto terá que decidir que os resultados son suficientes. Se os seus esforzos só están obtendo un 10% de melloras entón fai tempo que pasou o punto en que debería ter parado.

Non esqueza a visión xeral. Por exemplo, fronte a só tentar incrementar o rendemento dunha parte do código, pregúntese se realmente se precisa dita parte. Pode ser fornecida por outra parte do seu código? Poden os resultados de cálculos previos gardados e ser reusados? Podería non ser nin preciso optimizalo se é un lugar onde nunca vai ir o usuario para que poida notalo. Ou peor aínda, que o código xa estea optimizado e está facendo un cálculo moi grande agora para evitar facelo máis tarde. O código non se executa en separación e tampouco o fai nun proceso de optimizado.

# Suxestións

## O fundamental

Volva a executar a súa proba de rendemento despois de cada cambio que realice sobre o código e manteña un rexistro de todo o que cambia e de como afecta ao rendemento. Isto permítelle desfacer erros e tamén axúdalle a non repetilos.

Asegúrse de que o seu código é correcto e está libre de erros antes de optimizalo. Comprobe que permanece correcto e libre de erros desois de telo optimizado.

Optimizar ao nivel máis alto antes de optimizar os detalles.

Use o algoritmo correcto. O clásico exemplo de libro de texto é usar ordenación rápida no lugar de ordenación por burbulla. Existen moitos outros, algúns aforran memoria, alguns aforran CPU. Tamén debe ver que atallos de teclado pode crear: pode facelo máis rápido que unha ordenación rápida se está preparado para tomar certos compromisos.

A optimización é intercambio. Obter resultados mellora os cálculos pero aumenta a memoria en uso. Gardar datos ao disco aforra memoria pero custa tempo ao cargalos de novo desde o disco.

Asegúrese de elixir certa variedade de entradas que optimizar. SE non o fai é doado que remate cun trozo de código coidadosamente optimizado par aun campo e non para outros.

Evite as operacións caras: múltiples lecturas de disco pequenas. Use un montón de memoria para que a área de intercambio («swap») fágase innecesario. Evite calquera cousa que escriba ou lea innecesariamente do disco. A rede tamén é lenta. Evite tamén operacións gráficas que precisan unha resposta do servidor X.

## Trampas para os imprudentes

Estea atento aos efectos colaterais. Xeralmente son interaccións estranas entre diferentes seccións do código, unha extensión dunha parte pode retardar outra.

Ao cronometrar o tempo do código, incluso nun sistema parado, os eventos fora do programa engaden ruido aos resultados de tempo. Faga unha medida sobre múltiples execucións. Se o código é moi pequeno a resolución do tempo tamén é un problema. Neste caso mida o tempo que o equipo tarda en executar o código 100 ou 1000 veces. Se os tempos que está obtendo son algo superiores a uns poucos segundos todo debería estar correcto.

É moi doado perferse co perfilador. Existen historias de programadores optimizando o búcle de inactividade porque é onde se perdía todo o seu tempo. Non optimice código do que o usuario non se preocupe.

Lembre os resultados do servidor X. O uso de memoria do seu programa non inclúe os pixmaps almacenados nos procesos do servidor X, pero aínda seguen usando memoria. Use xrestop para ver os recursos que está usando o seu programa.

## Consellos de baixo nivel

Ao optimizar o uso de memoria considere a diferenza entre o uso de pico e o uso medio de memoria. Algunha memoria sempre está reservada, isto xeralmente é malo. Algunha está temporalmente reservada, isto pode ser aceptábel. Ferramentas como massif usan o concepto de espazo-tempo, o produto da memoria usada e o tempo durante o que estivo reservada.

Controle o tempo de trozos de código simplificados que só fan cousas esenciais, isto fornece un límite absoluto inferior no tempo que usará o código. Por exemplo, ao optimizar un búcle, controle o tempo do búcle baleiro. Se aínda é moito tempo calquera intento de optimización non axudará e deberá cambiar o seu deseño. Asegúrese de que o compilador non desoptimiza o búcle baleiro.

Mova o código fóra dos bucles internos. Un anaco de código máis complicado que se executa unha soa vez é moito máis rápido que un anaco de código máis sinxelo que se executa mil veces. Evite chamar habitualmente a código lento.

Give the compiler as many hints as possible. Use the const keyword. Use `G_INLINE_FUNC` for short, frequently called, functions. Look up `G_GNUC_PURE`, `G_LIKELY` and the other glib miscellaneous macros. Use the macros instead of gcc-specific keywords to ensure portability.

Non use linguaxes de ensamblado. O código non é portábel e pode ser máis rápido nun procesador que noutro, ademais non está garantizado que sea rápido en cada procesador que admite esa arquitectura (p.ex. Athlon contra Pentium 4).

Non rescriba unha rutina existente dunha biblioteca a non ser que estea seguro de que é demasiado lenta. Moitas rutinas de bibliotecas de uso intensivo pola CPU xa se optimizaron. Algunhas rutinas de bibliotecas son lentas, especialmente aquelas que realizan chamadas ao sistema operativo.

Minimice o número de bibliotecas ás que liga. Canto menor sexa o número de bibliotecas a ligar, máis rápido se iniciará o programa. É unha tarefa difícil en GNOME.

## Trucos de alto nivel

A ventaxa da concurrencia. Isto non significa simplemente usar varios procesadores, tamén significa aproveitarse do tempo que o usuario pasa pensando en que fará despois, para realizar algúns cálculos anticipados. Faga cálculos mentres se agarda a carga de datos desde o disco. Aprovéitese dos recursos múltiples, úseos todos á vez.

Engane. O usuario só ten que pensar que o equipo é rápido, non importa se realmente o é ou non. É o tempo entre a orde e a resposta o que importa, non importa se a resposta esta precalculada, cacheada ou se traballará nela en calquera momento posterior conveniente, sempre que o usuario obteña o que agarda.

Facer cousas no búcle ocioso. É máis doado programar usando multifíos e facer cousas por detrás dos ollos do usuario. Teña coidado, se pasa gasta moito tempo no bucle ocioso o seu programa podería volverse lento. Polo que de forma regular déalle de novo o control ao bucle principal.

Se todo isto falla, dígalle ao usuario que o código vai a executarse vai ser lento e móstrelle unha barra de progreso. Non estará tan contento con isto como se simplemente lle mostrara os resultados, porén cando menos saberá que o programa non se pechou ou ten problemas e pode ir a tomarse un café mentres.