GNU/Linux, Open Source, Cloud Computing, DevOps y más...

Uso excesivo de CPU al convertir imágenes con ImageMagick

22 comentarios

En 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


 

Sobre el autor

Daniel López Azaña
Arquitecto de soluciones Cloud

Emprendedor, generador de ideas y mente inquieta. Apasionado de las nuevas tecnologías, especialmente de los sistemas Linux y del software libre. Me gusta escribir además sobre actualidad tecnológica, Cloud Computing, DevOps, seguridad, desarrollo web y programación, SEO, ciencia, innovación, emprendimiento, etc.

DanielUso excesivo de CPU al convertir imágenes con ImageMagick

Artículos relacionados

Deja un comentario

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