Uso excesivo de CPU al convertir imágenes con ImageMagick

Imagemagick-logoEn ciertas versiones de ImageMagick se da el problema (seguramente debido a un bug) de que cuando se intenta convertir o manipular una imagen, ya sea desde la línea de comandos (comando convert) o a través de una de las numerosas API’s existentes (por ejemplo PHP), el uso de CPU se dispara más allá del 100% (debido a que este problema se da en sistemas multiprocesador) haciendo que nuestro sistema se vuelva tremendamente lento. Aparte de este uso excesivo de CPU, el proceso de conversión se queda bloqueado, no alcanzando a terminar nunca. Esto ocurre incluso con imágenes pequeñas con un tamaño de pocos kilobytes.

Tras investigar el problema, he llegado a la conclusión de que efectivamente se trata de un bug en las versiones de ImageMagick compiladas con la opción –enable-openmp en máquinas con varios procesadores o varios cores.

Por tanto, lo primero que debemos hacer para saber si la solución de este artículo nos servirá, es comprobar si la máquina dispone de varios procesadores o de varios núcleos: Cómo saber cuántos procesadores y núcleos tiene una máquina Linux.

A continuación comprobaremos si nuestra versión de ImageMagick tiene activada la característica OpenMP.

# convert --version
Version: ImageMagick 6.5.7-8 2010-12-02 Q16 http://www.imagemagick.org
Copyright: Copyright (C) 1999-2009 ImageMagick Studio LLC
Features: OpenMP 

Si el comando anterior muestra la línea “Features: OpenMP”, entonces todo encaja y nuestro problema de carga excesiva de CPU puede solucionarse de tres formas distintas:

  1. Actualizando a una nueva versión de ImageMagick o a una anterior suficientemente estable que no presente el bug causante del problema.
  2. Recompilando ImageMagick con la opción –disable-openmp para que no se haga uso de la característica de multiprocesador.
  3. Forzando a ImageMagick a utilizar sólo uno de los núcleos disponibles en el sistema para realizar la conversión.

Esta última es quizás la mejor solución a nuestro problema, pues probablemente ya habremos probado a actualizar ImageMagick a otra versión, y en muchos casos lo habremos instalado como un paquete de alguna de las distribuciones Linux disponibles, por lo que no nos resultará viable volver a compilar. Hay que destacar que el procedimiento que se mostrará a continuación realmente no soluciona el problema, sino que se trata de un workaround, un “truco” que nos permitirá utilizar ImageMagick sin que se reproduzca el mal uso de los recursos del sistema.

Limitar el número de núcleos utilizado con MAGICK_THREAD_LIMIT

La forma de obligar a ImageMagick a utilizar un sólo núcleo o procesador a la hora de realizar una conversión de una imagen es utilizando la variable de entorno MAGICK_THREAD_LIMIT. Esta variable debe tener el valor 1 y estar disponible en el entorno de ejecución del comando convert. Para ello editaremos el fichero añadiremos al fichero /etc/environment la línea MAGICK_THREAD_LIMIT=1:

# cat /etc/environment
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games"
LANG="es_ES.UTF-8"
LANGUAGE="es_ES.UTF-8"
MAGICK_THREAD_LIMIT=1

A continuación abriremos una nueva shell de comandos, ya que la actual no cargará dicha variable de entorno hasta que volvamos a iniciar sesión en el sistema.

Cómo establecer la variable MAGICK_THREAD_LIMIT en PHP

Si en lugar de utilizar ImageMagick desde la línea de comandos lo hacemos a través de las librerías disponibles para distintos lenguajes de programación como PHP, la solución anterior no funcionará y tendremos que cargar la variable MAGICK_THREAD_LIMIT=1 en el entorno de ejecución del intérprete PHP.

Me estoy refiriendo siempre al caso de utilizar las funciones nativas que utilizaremos en nuestro código, como “$im = new Imagick(“file.png”);” o “$im->readImageBlob($svgin);”, ya que si realizamos la conversión a través del comando “system(‘convert -resize 800×600 file1.png file2.png’);” estaremos llamando al comando convert del mismo modo que en el apartado anterior, en cuyo caso la solución sí es válida.

PHP desde la línea de comandos

env MAGICK_THREAD_LIMIT=1 php test.php

PHP ejecutado desde módulo mod_fcgid de Apache

En este caso cargaríamos la variable MAGICK_THREAD_LIMIT del comando /usr/bin/php5-cgi, que normalmente es ejecutado por un script intermedio correspondiente a un virtualhost concreto de Apache, el llamado FCGIWrapper que podremos encontrar en el fichero vhosts.conf correspondiente:

<Files ~ (\.php)>
   SetHandler fcgid-script
   FCGIWrapper /var/www/cgi-bin/cgi_wrapper/cgi_wrapper .php
   Options +ExecCGI
   allow from all
</Files>

# cat /var/www/cgi-bin/cgi_wrapper/cgi_wrapper
#! /bin/sh
export MAGICK_THREAD_LIMIT=1
exec /usr/bin/php5-cgi
Etiquetas:,

22 comentarios

  1. G 21/03/2012
  2. KWardle 26/03/2012
  3. KWardle 26/03/2012
  4. Michael 07/07/2012
  5. don bright 10/09/2012
  6. Noah 25/09/2012
  7. Dmitry 12/10/2012
  8. Mikhail 02/11/2012
  9. Sergey 13/12/2012
  10. seraph 05/02/2013
  11. Sumeet Kashyap 10/02/2013
  12. MarkusK 02/04/2013
  13. nikita 05/04/2013
  14. Leon 03/12/2013
  15. Morty 06/03/2014
  16. Steve 21/03/2015
    • Clau 06/04/2015
  17. Bodo 15/08/2016
  18. Bodo 15/08/2016

¡Deja tu comentario!

Tu dirección de correo electrónico no será publicada. Los campos necesarios están marcados *