<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Jesús Torres]]></title><description><![CDATA[Docente e investigador en el departamento de Ingeniería Informática de la Universidad de La Laguna y Director Académico del Máster en Desarrollo de Videojuegos ]]></description><link>https://jesustorres.es</link><generator>RSS for Node</generator><lastBuildDate>Sat, 11 Apr 2026 02:42:48 GMT</lastBuildDate><atom:link href="https://jesustorres.es/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Crear categorías de log para nuestros sistemas en Unreal Engine]]></title><description><![CDATA[En muchos libros y tutoriales sobre C++ en Unreal Engine se pueden ver ejemplos dónde se usa UE_LOG para mostrar mensajes que nos ayudan a depurar nuestro código y detectar problemas:
UE_LOG(LogTemp, Warning, TEXT("Hello, I'm here"));


💡
La macro U...]]></description><link>https://jesustorres.es/crear-categorias-de-log-para-nuestros-sistemas-en-unreal-engine</link><guid isPermaLink="true">https://jesustorres.es/crear-categorias-de-log-para-nuestros-sistemas-en-unreal-engine</guid><category><![CDATA[spanish]]></category><category><![CDATA[unreal-engine]]></category><category><![CDATA[GameDev]]></category><dc:creator><![CDATA[Jesús Torres]]></dc:creator><pubDate>Fri, 03 Jan 2025 16:29:34 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1735905451566/924e224e-c965-4916-85d0-0810158ca0b5.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>En muchos libros y tutoriales sobre C++ en Unreal Engine se pueden ver ejemplos dónde se usa <code>UE_LOG</code> para mostrar mensajes que nos ayudan a depurar nuestro código y detectar problemas:</p>
<pre><code class="lang-cpp">UE_LOG(LogTemp, Warning, TEXT(<span class="hljs-string">"Hello, I'm here"</span>));
</code></pre>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">La macro <code>UE_LOG</code> no es la única manera de mostrar mensajes. En Unreal Engine 5.2 se añadió <code>UE_LOGFMT</code>, que ofrece <a target="_self" href="https://dev.epicgames.com/documentation/en-us/unreal-engine/logging-in-unreal-engine#ue-logfmt">una interfaz más cómoda</a>. Y también esta <a target="_self" href="https://dev.epicgames.com/documentation/en-us/unreal-engine/fstring-in-unreal-engine#printtoviewport">AddOnScreenDebugMessages()</a></div>
</div>

<p>Imprimir mensajes de con <code>UE_LOG</code> en la categoría <code>LogTemp</code> es una buena opción durante la depuración de problemas.</p>
<p>Sin embargo, podemos querer dejar de forma permanente algunos de estos mensajes para que se emitan en condiciones que podrían ser problemáticas. En ese caso, usar <code>LogTemp</code> como categoría de los mensajes no es buena idea, porque se hace complicado determinar en qué sistema o componente está el problema. En su lugar, es preferible que definamos nuestras propias categorías, de forma que así sea más sencillo localizar los mensajes de un componente e identificar rápidamente el origen del problema.</p>
<p>En Unreal Engine, para definir una categoría de <em>log</em> necesitamos un archivo <code>.h</code> donde declaramos las nuevas categorías y un archivo <code>.cpp</code> donde las definimos. Por ejemplo: <code>LogCategories.h</code> y <code>LogCtegories.cpp</code>.</p>
<p>En la declaración de las nuevas categorías en el archivo <code>.h</code> usamos la macro <code>DECLARE_LOG_CATEGORY_EXTERN</code> así:</p>
<pre><code class="lang-cpp"><span class="hljs-comment">// LogCategories.h</span>

DECLARE_LOG_CATEGORY_EXTERN(LogInventorySystem, Log, All);
DECLARE_LOG_CATEGORY_EXTERN(LogMyAnimSystem, Log, All);
<span class="hljs-comment">//...</span>
</code></pre>
<p>De tal forma que:</p>
<ul>
<li><p><code>LogInventorySystem</code> es el nombre de la nueva categoría de <em>logs</em>.</p>
</li>
<li><p><code>Log</code> indica el nivel de verbosidad utilizado por defecto. Será el nivel usado si no se indica ninguno a usar <code>UE_LOG</code>. Los valores admitidos son: <code>Fatal</code>, <code>Error</code>, <code>Warning</code>, <code>Display</code>, <code>Log</code>, <code>Verbose</code> y <code>VeryVerbose</code>.</p>
</li>
<li><p>El tercer argumento indica el nivel de verbosidad más alto que será incluido al compilar el proyecto. Sí, por ejemplo, se indica <code>All</code>, se incluyen todos los niveles, pero si se indica <code>Warning</code>, no es posible ver mensajes en los niveles de verbosidad <code>Display</code>, <code>Log</code>, <code>Verbose</code> o <code>VeryVerbose</code>. Por tanto, este argumento ofrece una forma sencilla de suprimir todos los mensajes a partir de cierto nivel de verbosidad en la categoría indicada.</p>
</li>
</ul>
<p>Luego, en la definición en el archivo <code>.cpp</code> usamos la macro <code>DEFINE_LOG_CATEGORY</code> indicando solo el nombre de la nueva categoría:</p>
<pre><code class="lang-cpp"><span class="hljs-comment">// LogCategories.cpp</span>

DEFINE_CATEGORY_EXTERN(LogInventorySystem);
DEFINE_CATEGORY_EXTERN(LogMyAnimSystem);
<span class="hljs-comment">//...</span>
</code></pre>
<p>Finalmente, podemos incluir <code>LogCategories.h</code> en aquellos archivos donde queramos usar una de estas categorías y utilizarla con <code>UE_LOG</code> con normalidad:</p>
<pre><code class="lang-cpp"><span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">"LogCategories.h"</span></span>

UE_LOG(LogInventorySystem, Warning, TEXT(<span class="hljs-string">"Inventory component not found"</span>));
UE_LOG(LogInventorySystem, Log, TEXT(<span class="hljs-string">"%d items added"</span>), NumOfItems);
</code></pre>
<p>O con la nueva macro <code>UE_LOGFMT</code>:</p>
<pre><code class="lang-cpp"><span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">"LogCategories.h"</span></span>

UE_LOGFMT(LogInventorySystem, Warning, <span class="hljs-string">"Inventory component not found: {0}"</span>, GetName());
UE_LOGFMT(LogInventorySystem, Log, <span class="hljs-string">"{Count} items added: {OwnerName}"</span>,
    (<span class="hljs-string">"Count"</span>, NumOfItems), (<span class="hljs-string">"OwnerName"</span>, GetOwner()-&gt;GetName()));
</code></pre>
<h1 id="heading-referencias-adicionales">Referencias adicionales</h1>
<ul>
<li><p><a target="_blank" href="https://dev.epicgames.com/documentation/en-us/unreal-engine/logging-in-unreal-engine">Unreal Engine 5.5 Documentation — Logging in Unreal</a></p>
</li>
<li><p><a target="_blank" href="https://dev.epicgames.com/community/snippets/Vm9/unreal-engine-print-to-screen-in-c">Epic Development Community — Snippets — Print to screen in C++</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Custom Movement Mode en C++ — Wall Run]]></title><description><![CDATA[Este artículo fue publicado originalmente como un tutorial en la Epic Developer Community.

Tutoriales
En el siguiente vídeo muestro cómo funciona el Custom Movement Mode del componente CharacterMovementComponent en C++ y como podemos usarlo para aña...]]></description><link>https://jesustorres.es/custom-movement-mode-en-cpp-wall-run</link><guid isPermaLink="true">https://jesustorres.es/custom-movement-mode-en-cpp-wall-run</guid><category><![CDATA[unreal-engine]]></category><category><![CDATA[C++]]></category><category><![CDATA[Game Development]]></category><category><![CDATA[spanish]]></category><dc:creator><![CDATA[Jesús Torres]]></dc:creator><pubDate>Wed, 01 Jan 2025 21:54:44 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1735828090142/0fb31fdc-f653-497d-b5c0-5aa5661fdc19.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>Este artículo fue</em> <a target="_blank" href="https://dev.epicgames.com/community/learning/tutorials/xj21/unreal-engine-custom-movement-mode-en-c-wall-run"><em>publicado originalmente</em></a> <em>como un tutorial en la Epic Developer Community.</em></p>
<hr />
<h1 id="heading-tutoriales">Tutoriales</h1>
<p>En el siguiente vídeo muestro cómo funciona el <strong>Custom Movement Mode</strong> del componente <code>CharacterMovementComponent</code> en C++ y como podemos usarlo para añadir a nuestros personajes un nuevo movimiento. Para ilustrar su uso, implementamos un sencillo prototipo del movimiento de <em>correr por la pared</em> (Wall Run).</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=eagZT49l7rw">https://www.youtube.com/watch?v=eagZT49l7rw</a></div>
<p> </p>
<p>Mientras que en este, terminamos el prototipo añadiendo algunas mejoras que faltaban, como el uso de animaciones adecuadas o curvas para ajustar algunos parámetros del movimiento.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=Y1mF2gJ9qhU">https://www.youtube.com/watch?v=Y1mF2gJ9qhU</a></div>
<p> </p>
<p>Al final de este artículo hay una lista de mejoras pendientes que podrían ser interesantes de implementar.</p>
<h1 id="heading-modos-de-movimiento">Modos de movimiento</h1>
<p>Como es bien sabido, los actores de la clase <code>Character</code> incluyen un componente <code>CharacterMovementComponent</code> que se encarga del movimiento del actor por la escena, según el <strong>modo de movimiento</strong> activo y la entrada recibida del jugador o —en el caso de los Personajes No Jugador (PNJ)— las indicaciones de la IA.</p>
<p>El <code>CharacterMovementComponent</code> soporta por defecto múltiples modos de movimiento, permitiendo al componente cambiar su comportamiento, procesando de manera diferente la entrada del jugador y considerando, según el caso, diferentes fenómenos físicos:</p>
<ul>
<li><p><strong>Walking</strong>, utilizado cuando el personaje camina o corre por una superficie.</p>
</li>
<li><p><strong>Falling</strong>, empleado cuando el personaje está cayendo o saltando. En este modo se simula el efecto de la gravedad, que hace que el personaje caiga al vacío.</p>
</li>
<li><p><strong>Swimminng</strong>, utilizado cuando el personaje tiene que nadar a través de un líquido, de manera que el componente tiene que simular los efectos de la gravedad y la flotabilidad en el medio donde nada.</p>
</li>
<li><p><strong>Flying</strong>, usado cuando el personaje vuela, por lo que puede desplazarse con total libertad en 3D, ignorando los efectos de la gravedad.</p>
</li>
</ul>
<p>Además de estos modos, el Ch<code>aracterMovementComponent</code> soporta varios tipos de movimiento adicionales que se pueden utilizar sin cambiar de modo. Por ejemplo, en el modo <strong>Walking</strong>, el personaje puede agacharse y caminar agachado o puede saltar.</p>
<p>Todo esto convierte al actor <code>Character</code> y a <code>CharacterMovementComponent</code> en herramientas muy potentes, que nos permiten comenzar a prototipar y probar cualquier idea rápidamente, sin tener que consumir tiempo y recursos en implementar un controlador propio.</p>
<h1 id="heading-anadir-nuevos-movimientos">Añadir nuevos movimientos</h1>
<p>Sin embargo, en muchas ocasiones necesitamos un tipo de movimiento no incluido por defecto en <code>CharacterMovementComponent</code>. Esto ocurre, por ejemplo, si queremos que nuestro personaje pueda escalar, esquivar, usar escaleras de mano o hacer algún tipo de <em>parkour</em>.</p>
<p>El <code>CharacterMovementComponent</code>  ofrece diversas formas de añadir un nuevo tipo del movimiento, siendo mejor una u otra según el caso concreto:</p>
<ul>
<li><p><strong>Launch</strong>. El método <code>CharcterMovementComponent::Launch()</code> permite lanzar al personaje con la dirección y velocidad indicada. Suele ser muy útil para implementar ciertos movimientos sencillos, como la <em>esquiva</em> (<em>dash</em>).</p>
</li>
<li><p><strong>Root Motion Source</strong>. Utilizando  <strong>root motion</strong>, el movimiento del personaje en la escena viene determinado por la animación que se reproduce en la malla esqueletal. Sin embargo, este mecanismo ha sido modificado en el <code>CharacterMovementComponent</code> para que la información del movimiento también pueda ser generada mediante código. Este código se tiene que implementar en un <strong>Root Motion Source</strong> y este se activa en el <code>CharacterMovementComponent</code> cuando se quiere iniciar ese tipo de movimiento.</p>
<p>  Este sistema es muy versátil y permite crear todo tipo de movimientos. Es especialmente útil para movimientos que solo deben ejecutarse durante un breve periodo de tiempo, para que luego el personaje vuelva al comportamiento normal determinado por el modo de movimiento activo.</p>
</li>
<li><p><strong>Custom Movement Mode</strong>. Cuando el personaje puede permanecer durante bastante tiempo moviéndose de cierta forma, puede ser más interesante tener un modo de movimiento propio para ese tipo de movimiento.</p>
<p>  El modo <strong>Custom</strong> es uno de los modos de movimiento soportados por el <code>CharacterMovementComponent</code>, junto a <strong>Walking</strong>, <strong>Falling</strong> y otros modos mencionados anteriormente. La diferencia es que en este modo el personaje no se mueve, pues es responsabilidad de los programadores implementar el código correspondiente según cómo desean que se mueva el personaje.</p>
</li>
</ul>
<p>En el vídeo que acompaña a este tutorial se muestra como hacer uso del <strong>Custom Movement Mode</strong> en C++.</p>
<h1 id="heading-custom-movement-mode">Custom Movement Mode</h1>
<p>El modo <strong>Custom</strong> permite a los desarrolladores implementar varios modos nuevos de movimiento. Para ello, en el momento de activar el modo Custom, se debe especificar un identificador del submodo deseado. Esto se puede observar en nodo Set Movement Mode, con el que se puede cambiar el modo de movimiento activo de un componente <code>CharacterMovementComponent</code>:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td></td></tr>
</thead>
<tbody>
<tr>
<td>Nodo Set Movement Mode en Blueprint</td></tr>
</tbody>
</table>
</div><p>El valor indicado en <strong>New Custom Mode</strong> al activar el modo <strong>Custom</strong> es entregado al código desarrollado a medida por los programadores para este modo de movimiento. De esta forma se puede saber el submodo activo y, por tanto, se pueden hacer cosas diferentes en cada caso.</p>
<h1 id="heading-sobre-el-tutorial">Sobre el tutorial</h1>
<p>Comentemos algunos detalles adicionales sobre el vídeo con el que empezamos este tutorial.</p>
<h2 id="heading-proyecto-inicial">Proyecto inicial</h2>
<p>El proyecto está basado en la plantilla Third Person en Blueprint. Solo se han importado previamente:</p>
<ul>
<li><p>Animaciones Wall Run Left y Wall Run Right, extraidas del paquete <a target="_blank" href="https://www.fab.com/listings/9018f998-dd97-4e16-a8b3-b0900405b70f">All-IN-ONE PARKOUR</a>.</p>
</li>
<li><p>Una clase <code>AWRCharacterBase</code> en C++ derivada de <code>ACharacter</code> y de la que, a su vez deriva el Blueprint del personaje de la plantilla <code>BP_ThirdPersonCharacter</code>.</p>
</li>
<li><p>Una malla estática de 300x300 cm. para construir las paredes sobre las que correrá el personaje.</p>
</li>
</ul>
<h2 id="heading-posibles-mejoras">Posibles mejoras</h2>
<p>El modo desarrollado solo pretende ilustrar la creación de un <strong>Custom Movement Mode</strong>, por lo que está lejos de mostrar una implementación completa. Estas podrían ser algunas mejoras al código mostrado.</p>
<h3 id="heading-tiempo-de-recuperacion-cool-down">Tiempo de recuperación (cool down)</h3>
<p>Como condición para activar el nuevo modo Wall Running se podría comprobar que haya pasado cierto tiempo configurable de recuperación. Esto evitaría que el jugador pueda volver a utilizar el nuevo modo de movimiento demasiado pronto.</p>
<p>Por ejemplo, evitaría que si mientras está en este modo el personaje cae, pueda volver a iniciar el modo <strong>Wall Running</strong> un poco más abajo en la misma pared, evitando realmente la caída.</p>
<h3 id="heading-anadir-condicion-para-que-velocidad-y-forward-ten-la-misma-direccion-y-sentido">Añadir condición para que velocidad y forward ten la misma dirección y sentido</h3>
<p>En <code>CanStartWallRunning()</code> se puede añadir la comprobación de que la velocidad del personaje <code>Velocity</code> y el <em>forward</em> del actor tengan la misma dirección y sentido para entrar en el modo <code>Wall Running</code>.</p>
<pre><code class="lang-cpp"><span class="hljs-keyword">const</span> <span class="hljs-keyword">bool</span> bAreVelocityAndForwardNearlyEqual = FVector::DotProduct(Velocity.GetSafeNormal2D(),
    GetOwner()-&gt;GetActorForwardVector()) &gt; <span class="hljs-number">0.7f</span>;

<span class="hljs-comment">// ...</span>

<span class="hljs-keyword">return</span> bIsWallRunnable &amp;&amp; bIsFalling &amp;&amp; bIsNearMaxSpeed &amp;&amp; bIsNearMaxInput
    &amp;&amp; bAreVelocityAndForwardNearlyEqual &amp;&amp; bIsMovementParallelToWall;
</code></pre>
<p>Así obligamos al jugador a que tenga que mirar y mover al personaje en la dirección del muro para comenzar a correr sobre él. Si en el último momento el jugador cambia la dirección de la cámara, el personaje no entrará en el modo <strong>Wall Running</strong> y caerá.</p>
<h3 id="heading-integracion-con-el-modo-falling">Integración con el modo Falling</h3>
<p>Actualmente, para entrar en modo <strong>Wall Running</strong> el personaje debe estar primero en modo <strong>Falling</strong>. Cuando el <code>CharacterMovementMode</code> mueve al personaje en este modo puede ocurrir una colisión, que detectamos mediante el evento <code>OnComponentHit</code> de la cápsula para comprobar si el personaje ha llegado aún muro por el que puede correr.</p>
<p>Sin embargo, si examinamos el código de <code>CharacterMovementMode</code> veremos que no es así como se interrelacionan los diferentes modos implementados. Por lo general, están mucho más acoplados, siendo muy común añadir nuevos modos modificando directamente la clase <code>CharacterMovementMode</code>.</p>
<p>Por ejemplo, podemos ir a <code>PhysFalling()</code> —donde se implementa el modo <strong>Falling</strong>— y buscar dónde se mueve al personaje:</p>
<pre><code class="lang-cpp"><span class="hljs-comment">// ...</span>

<span class="hljs-function">FHitResult <span class="hljs-title">Hit</span><span class="hljs-params">(<span class="hljs-number">1.f</span>)</span></span>;
SafeMoveUpdatedComponent( Adjusted, PawnRotation, <span class="hljs-literal">true</span>, Hit);

<span class="hljs-comment">// ...</span>

<span class="hljs-keyword">float</span> LastMoveTimeSlice = timeTick;
<span class="hljs-keyword">float</span> subTimeTickRemaining = timeTick * (<span class="hljs-number">1.f</span> - Hit.Time);

<span class="hljs-keyword">if</span> ( IsSwimming() ) <span class="hljs-comment">//just entered water</span>
{
    remainingTime += subTimeTickRemaining;
    StartSwimming(OldLocation, OldVelocity, timeTick, remainingTime, Iterations);
    <span class="hljs-keyword">return</span>;
}

<span class="hljs-comment">//...</span>
</code></pre>
<p>La función encargada de mover el personaje es <code>SafeMoveUpdatedComponent()</code>, que devuelve una estructura <code>FHitResult</code> con información en caso de colisión. Por tanto, en lugar de usar el evento <code>OnComponentHit</code>, se podría comprobar directamente la colisión a la salida de <code>SafeMoveUpdatedComponent()</code> y llamar a nuestro <code>CanContinueWallRunning()</code> para comprobar si debemos entrar en el modo <strong>Wall Running</strong>.</p>
<p>En ese caso, si se activa el modo <strong>Wall Running</strong>, se puede llamar después a <code>StartNewPhysics()</code> indicando el tiempo restante del <code>DeltaTime</code> —es decir, usando el resultado <code>DeltaTime - Hit.Time</code> como nuevo <code>DeltaTime</code>—. De esta forma, se llamaría a nuestro nuevo <code>PhysWallRunning()</code> inmediatamente, para que el personaje comience a moverse en el nuevo modo de movimiento sin esperar al siguiente <em>frame</em>.</p>
<p>Se puede ver un ejemplo de esto en el código anterior cuando se comprueba <code>IsSwimming()</code> y, en caso afirmativo, se llama a <code>StartSwimming()</code>. De esta forma, el personaje pueden comenzar a nada inmediatamente.</p>
<h3 id="heading-animaciones">Animaciones</h3>
<p>El resultado podría mejorarse si dispusiéramos de alguna animación de transición entre la que se usa en bucle mientras se está cayendo y las animaciones de Wall Run. También convendría ajustar el <strong>Control Rig</strong> del personaje para que los pies se posicionen correctamente tanto al correr en el suelo como a lo largo de una pared.</p>
<h1 id="heading-recursos-adicionales">Recursos adicionales</h1>
<p>Estos son algunos recursos que pueden resultar útiles para seguir profundizando en el tema*</p>
<ul>
<li><p><a target="_blank" href="https://dev.epicgames.com/documentation/en-us/unreal-engine/programming-with-cplusplus-in-unreal-engine">Unreal Engine 5.5 Documentation — Programming with C++</a>.</p>
</li>
<li><p><a target="_blank" href="https://dev.epicgames.com/documentation/en-us/unreal-engine/setting-up-character-movement">Unreal Engine 5.5 Documentation — Setting Up Character Movement</a>.</p>
</li>
<li><p><a target="_blank" href="https://dev.epicgames.com/documentation/en-us/unreal-engine/character-movement-component?application_version=4.27">Unreal Engine 4.27 Documentation — Character Movement Component</a>.</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Apuntes de Sistemas Operativos]]></title><description><![CDATA[Cuando comencé a dar clases de sistemas operativos, empecé a elaborar unos apuntes a partir de distintos libros y otras fuentes de Internet.
Inicialmente, solo eran un apoyo para preparar las clases cada año. Con el tiempo, les fui dando formato y ac...]]></description><link>https://jesustorres.es/apuntes-de-sistemas-operativos</link><guid isPermaLink="true">https://jesustorres.es/apuntes-de-sistemas-operativos</guid><category><![CDATA[Linux]]></category><category><![CDATA[spanish]]></category><category><![CDATA[notes]]></category><category><![CDATA[operating system]]></category><category><![CDATA[Windows]]></category><category><![CDATA[ull-esit-soa]]></category><dc:creator><![CDATA[Jesús Torres]]></dc:creator><pubDate>Wed, 19 Jul 2023 23:40:51 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/BStW5kYXw4E/upload/180a40b9e1ea7f4e5e35fafd767aa085.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Cuando comencé a dar clases de sistemas operativos, empecé a elaborar unos apuntes a partir de distintos libros y otras fuentes de Internet.</p>
<p>Inicialmente, solo eran un apoyo para preparar las clases cada año. Con el tiempo, les fui dando formato y acabé compartiéndolos con los estudiantes de cada curso. Aunque hace tiempo que son públicos, ahora dejo los enlaces por aquí, por si pueden resultar interesantes a más gente que quiera aprender sobre sistemas operativos.</p>
<p>Los apuntes están hechos con <a target="_blank" href="https://asciidoctor.org/">Asciidoctor</a> y las fuentes están disponibles en <a target="_blank" href="https://github.com/ull-esit-sistemas-operativos/ssoo-apuntes">GitHub</a>. Desde la sección <a target="_blank" href="https://github.com/ull-esit-sistemas-operativos/ssoo-apuntes/releases"><em>releases</em></a> de ese mismo repositorio, se puede descargar la última versión en PDF. Mientras que la última versión en HTML está publicada en:</p>
<p><a target="_blank" href="https://ull-esit-sistemas-operativos.github.io/ssoo-apuntes/">https://ull-esit-sistemas-operativos.github.io/ssoo-apuntes/</a></p>
<p>Los apuntes cubren los temas:</p>
<ol>
<li><p><strong>Introducción a los sistemas operativos</strong>: esta sección proporciona una descripción general de los sistemas operativos, incluyendo su historia, funciones y tipos.</p>
</li>
<li><p><strong>Organización de los sistemas operativos</strong>: esta sección se centra en la organización interna de los sistemas operativos, considerando sus componentes, servicios e interfaces; además de ofrecer una visión superficial sobre cómo funcionan.</p>
</li>
<li><p><strong>Gestión de procesos</strong>: esta sección se centra en cómo los sistemas operativos gestionan los procesos.</p>
</li>
<li><p><strong>Gestión de memoria</strong>: esta sección se centra en cómo los sistemas operativos gestionan la memoria principal.</p>
</li>
<li><p><strong>Gestión del almacenamiento</strong>: esta sección se centra en como se gestionan los dispositivos de almacenamiento secundario y los sistemas de archivos.</p>
</li>
</ol>
<p>A lo largo de los distintos capítulos se hace uso de algunos códigos de ejemplo. Estos códigos son partes de programas en C o C++ disponibles al completo en el siguiente repositorio:</p>
<p><a target="_blank" href="https://github.com/ull-esit-sistemas-operativos/ssoo-ejemplos">https://github.com/ull-esit-sistemas-operativos/ssoo-ejemplos</a></p>
<p>Mejoro y actualizo el material poco a poco cada año y aún me queda bastante trabajo para reemplazar por completo algunas de las figuras originales, pero espero que a alguien le pueda ser útil.</p>
]]></content:encoded></item><item><title><![CDATA[PowerShell vs. Bash para usuarios de Linux]]></title><description><![CDATA[Los sistemas Windows actuales permiten usar la shell Bash gracias al Windows Subsystem for Linux (WSL). Si somos usuarios habituales de Linux y, por algún motivo, nos vemos forzados a usar Windows, WSL nos ofrece una manera sencilla de usar una inter...]]></description><link>https://jesustorres.es/powershell-vs-bash-para-usuarios-de-linux</link><guid isPermaLink="true">https://jesustorres.es/powershell-vs-bash-para-usuarios-de-linux</guid><category><![CDATA[Bash]]></category><category><![CDATA[Powershell]]></category><category><![CDATA[spanish]]></category><dc:creator><![CDATA[Jesús Torres]]></dc:creator><pubDate>Sun, 11 Jun 2023 10:47:36 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1686324148860/0d281461-ef60-4fcb-bc3f-399e80ab3b9b.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Los sistemas Windows actuales permiten usar la <em>shell</em> Bash gracias al Windows Subsystem for Linux (WSL). Si somos usuarios habituales de Linux y, por algún motivo, nos vemos forzados a usar Windows, WSL nos ofrece una manera sencilla de usar una interfaz de comandos y unas herramientas que conocemos bien y con las que, seguramente, nos sintamos mucho más cómodos que con las nativas de Windows.</p>
<p>Sin embargo, a la hora de administrar sistemas Windows, recurrir a las herramientas del ecosistema de Linux no suele ser la mejor opción porque presentan algunas limitaciones al usarlas fuera de su entorno original.</p>
<p>En este artículo hablaremos de las diferencias de base entre PowerShell y Bash y de como estas diferencias vienen condicionadas por las características del ecosistema para el que fueron diseñadas.</p>
<h1 id="heading-antes-de-powershell">Antes de PowerShell</h1>
<p>Hasta hace muy poco la interfaz de línea de comando por defecto de Windows era el <strong>Símbolo del sistema</strong> o <strong><em>Command Prompt</em></strong>.</p>
<p>Esta era la interfaz de línea de comandos original de Windows y tiene sus raíces en el antiguo sistema operativo MS-DOS. MS-DOS fue un sistema operativo basado en texto, que se desarrolló para los primeros PC y que fue popular en los años 80 y principios de los 90, antes de que las interfaces gráficas de usuario se volvieran comunes.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1686324196389/990194ad-4be1-4fb5-a8b6-cbaeced3533c.png" alt="Interfaz de MS-DOS 6 ejecutando el comando dir." class="image--center mx-auto" /></td></tr>
</thead>
<tbody>
<tr>
<td>Interfaz de MS-DOS 6 ejecutando el comando <code>dir</code>.</td></tr>
</tbody>
</table>
</div><p>Uno de los componentes de MS-DOS —y otras versiones de DOS— era el programa <code>COMMAND.COM</code>, que se ejecutaba al terminar el arranque del sistema y que implementaba la interfaz de línea de comandos. Esta interfaz y su lenguaje de scripting —conocido como <em>archivos batch</em> (.BAT)— estaban muy limitados, en comparación con las <em>shells</em> de Unix/Linux —como BASH—, principalmente por las limitaciones del propio sistema y del hardware sobre el que iba a ejecutarse.</p>
<p>Cuando Microsoft introdujo Windows, inicialmente se ejecutaba como una interfaz gráfica de usuario sobre MS-DOS. Con el tiempo, Windows evolucionó para convertirse en un sistema operativo independiente e introdujo una nueva interfaz de línea de comandos identificada como el <strong>Símbolo del sistema</strong>. Esta interfaz era implementada por el programa <code>cmd.exe</code>, pero sus características era muy similares a la de la antigua interfaz de MS-DOS.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1686324208254/f80c4791-c11a-4256-9b2e-c5e7a63d13d8.png" alt="Icono del Command Prompt de Windows NT 3.1 con el logo de MS-DOS." class="image--center mx-auto" /></td></tr>
</thead>
<tbody>
<tr>
<td>Icono del <em>Command Prompt</em> de Windows NT 3.1 con el logo de MS-DOS.</td></tr>
</tbody>
</table>
</div><p>Además, <code>cmd.exe</code> está estrechamente vinculado a la arquitectura del sistema operativo Windows y no se puede portar fácilmente a o<em>t</em>ros sistemas operativos. Esto significa que los scripts y comandos que funcionan en <code>cmd.exe</code> a menudo no funcionan en otros sistemas operativos sin modificaciones significativas.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1686324221105/e7fc77fe-1b06-436c-9598-7ec829ee8c8a.png" alt="Símbolo del sistema en Windows 10." class="image--center mx-auto" /></td></tr>
</thead>
<tbody>
<tr>
<td>Símbolo del sistema en Windows 10.</td></tr>
</tbody>
</table>
</div><p>PowerShell fue introducido por Microsoft en 2006 para abordar muchas de estas limitaciones. PowerShell es un <em>shell</em> y lenguaje de scripting mucho más potente que <code>cmd.exe</code>, con soporte para scripting basado en objetos y un conjunto de características que es comparable al de las <em>shells</em> Unix/Linux. PowerShell también ha sido portado a otros sistemas operativos, incluyendo Linux y macOS.</p>
<p>Aunque <code>cmd.exe</code> sigue estando disponible en las versiones modernas de Windows —y sigue siendo posible ejecutar archivos .BAT— PowerShell se ha convertido en la <em>shell</em> por defecto del sistema y suele ser el preferido para muchas tareas relacionadas con la administración de sistemas.</p>
<h1 id="heading-por-que-powershell">¿Por qué PowerShell?</h1>
<p>Desde las primeras versiones de Windows, Microsoft siempre ha tenido predilección por el desarrollo de interfaces gráficas de usuario (GUI). Esto no solo se aprecia en la evolución de Windows, sino también en el desarrollo de muchas de las aplicaciones y tecnologías asociadas, como es el caso de la mayoría de los asistentes y herramientas de configuración y administración del sistema.</p>
<p>Sin embargo, con el tiempo, se dieron cuenta de que las GUI, a pesar de su accesibilidad y facilidad de uso para la mayoría de los usuarios, presenta importantes limitaciones cuando se trata de administrar sistemas y de automatizar tareas, especialmente a gran escala. PowerShell fue la respuesta a esta necesidad.</p>
<p>La intención original era incluir en Windows un conjunto de herramientas similares a las de Unix<sup id="1"><a class="post-section-overview" href="#fn1">1</a></sup>. Sin embargo, esto no funcionaba también como cabía espera. El motivo es que el ecosistema de Unix está construido en torno a los archivos de texto. En Unix/Linux la configuración e información del núcleo de sistema, servicios y aplicaciones está disponible en forma de archivos de texto, por lo que las múltiples herramientas de procesamiento de texto que acompañan a Bash son, efectivamente, herramientas de gestión.</p>
<p>Sin embargo, Windows es un ecosistema construido en torno a API y a objetos binarios —como las interfaces <a target="_blank" href="http://es.wikipedia.org/wiki/Component_Object_Model">COM</a>, <a target="_blank" href="https://es.wikipedia.org/wiki/Windows_Management_Instrumentation">WMI</a>, el <a target="_blank" href="https://es.wikipedia.org/wiki/Active_Directory">Directorio Activo</a>, el Registro del sistema, etc.— por lo que las herramientas de procesamiento de texto tradicionales de Unix no pueden ayudar demasiado en la gestión del sistema. Es debido a esto desarrollaron PowerShell, con el objetivo de obtener una herramienta comparable a las <em>shells</em> de Unix/Linux pero en el ecosistema de Windows.</p>
<h1 id="heading-secuencias-de-caracteres-vs-objetos">Secuencias de caracteres vs. Objetos</h1>
<p>En Bash y otras <em>shells</em> de Unix/Linux, la mayoría de las operaciones se realizan sobre secuencias de caracteres. La salida de un comando, por medio de su salida estándar, es una secuencia de caracteres, que se puede redirigir a un archivo o a otro comando utilizando los operadores '&gt;' y '|', respectivamente. Igualmente, los comandos pueden aceptar una secuencia de caracteres a través de su entrada estándar, que puede provenir de un archivo o de la salida de otro comando utilizando los operadores '&lt;' y '|', respectivamente. Y las variables que se utilizan en los scripts, almacenan y se sustituyen como secuencias de caracteres.</p>
<p>Por ejemplo, el siguiente comando puede usarse para listar y filtrar procesos:</p>
<pre><code class="lang-bash">ps aux | grep python
</code></pre>
<p>El comando <code>ps aux</code> genera un listado detallado de todos los procesos en ejecución, con una línea de información para cada proceso. La salida del comando devuelve dicha información como una secuencia de caracteres. El comando <code>grep python</code> filtra este texto para mostrar solo las líneas que contienen la palabra "python". Si esta palabra aparece en el nombre del comando, es probable que se trate de una ejecución del intérprete del lenguaje Python.</p>
<p>El comando <code>grep python</code> no busca la palabra en una propiedad específica del proceso, sino en toda la línea que contiene su información. Si, por ejemplo, solo interesa listar los procesos del usuario “python” o los procesos del comando “python”, haría falta buscar otra solución.</p>
<p>En contraste, PowerShell maneja la conexión entre comandos de manera diferente. En lugar de pasar secuencias de caracteres, PowerShell puede pasar objetos completos —de hecho, son objetos de .NET— dónde cada uno es una entidad con propiedades y métodos. Esto permite que los comandos que se encadenan en una tubería de PowerShell mediante el operador ‘|’, sean más conscientes de la estructura y el contenido de la información que reciben.</p>
<p>Por ejemplo, considera el comando equivalente en PowerShell del comando de Bash mencionado anteriormente:</p>
<pre><code class="lang-powershell"><span class="hljs-built_in">Get-Process</span> | <span class="hljs-built_in">Where-Object</span> { <span class="hljs-variable">$_</span>.ProcessName <span class="hljs-operator">-like</span> <span class="hljs-string">"*python*"</span> }
</code></pre>
<p>El comando <code>Get-Process</code> genera una lista de objetos de proceso, cada uno de los cuales tiene propiedades como <code>ProcessName</code>, <code>Id</code>, etc. Mientras que el comando <code>Where-Object</code> itera sobre los objetos evaluando la condición indicada, para filtrarlos basándose en sus propiedades; en lugar de buscar el texto "python" en una secuencia de caracteres sin estructura, como hace <code>grep</code>. Concretamente, en el ejemplo anterior, <code>Where-Object</code> extrae el valor de la propiedad <code>ProcessName</code> del objeto actual y comprueba si esta contiene la subcadena "python". Es decir, que se pueden comprobar fácilmente condiciones en cualquiera de las propiedades de cada proceso del listado devuelto por <code>Get-Process</code>.</p>
<p>Aunque lo pueda parecer, el resultado de <code>Where-Object</code> no es texto, sino una lista de objetos que cumplen la condición indicada. Como la salida del <code>Where-Object</code> no va a ser guardada en una variable ni a usarla con otro comando, el intérprete de PowerShell la convierte en texto para mostrársela al usuario en la consola.</p>
<p>Obviamente, PowerShell puede procesar textos como lo hace Bash. Tiene herramientas propias, que admiten y devuelven secuencias de caracteres, además de poder invocar las herramientas típicas de los sistemas Unix, si están disponibles en el sistema.</p>
<p>Tanto en Unix/Linux como en Windows, cualquier proceso puede tener una entrada y una salida estándar, siendo el mecanismo por el que las <em>shells</em> —incluidas Bash y PowerShell— pueden conectar la salida de texto de un comando con la entrada de otro. La diferencia es que, en PowerShell, adicionalmente, las funciones y los <em>cmdlets</em> permiten implementar comandos que reciben y devuelven objetos, en lugar de solo secuencias de caracteres.</p>
<p>En PowerShell ambos mundos se pueden unir fácilmente. Por ejemplo, supongamos que tenemos un listado de libros en un archivo de texto <code>libros.json</code> en formato JSON.</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"books"</span>: [
        {<span class="hljs-attr">"title"</span>: <span class="hljs-string">"1984"</span>, <span class="hljs-attr">"author"</span>: <span class="hljs-string">"George Orwell"</span>, <span class="hljs-attr">"year"</span>: <span class="hljs-number">1949</span>},
        {<span class="hljs-attr">"title"</span>: <span class="hljs-string">"Un mundo feliz"</span>, <span class="hljs-attr">"author"</span>: <span class="hljs-string">"Aldous Huxley"</span>, <span class="hljs-attr">"year"</span>: <span class="hljs-number">1932</span>},
        {<span class="hljs-attr">"title"</span>: <span class="hljs-string">"Fahrenheit 451"</span>, <span class="hljs-attr">"author"</span>: <span class="hljs-string">"Ray Bradbury"</span>, <span class="hljs-attr">"year"</span>: <span class="hljs-number">1953</span>}
    ]
}
</code></pre>
<p>Filtrar libros según algún criterio y seleccionar varias propiedades de este listado, usando solamente herramientas de procesamiento de texto, puede ser muy complejo. Sin embargo, podemos convertir el contenido del archivo en listas de objetos, para iterar fácilmente sobre ellos, filtrar y seleccionar la información que queremos mostrar al usuario.</p>
<pre><code class="lang-powershell">(<span class="hljs-built_in">Get-Content</span> libros.json | <span class="hljs-built_in">ConvertFrom-Json</span>).books |
    <span class="hljs-built_in">Where-Object</span> { <span class="hljs-variable">$_</span>.year <span class="hljs-operator">-lt</span> <span class="hljs-number">1950</span> } | <span class="hljs-built_in">ForEach-Object</span> { <span class="hljs-variable">$_</span>.title }
</code></pre>
<h1 id="heading-cmdlets-en-powershell">Cmdlets en PowerShell</h1>
<p>Los <em>cmdlets</em> —pronunciado como <em>command-let</em>— son un tipo de comando de PowerShell que se implementan mediante clases de .NET —heredando de la clase <code>System.Management.Automation.Cmdlet</code>—. Generalmente, se usa un lenguaje como C# y se compilan en archivos .DLL, que PowerShell carga para ejecutar el comando dentro del contexto del intérprete o el script actual. Por tanto, son más ligeros que otros tipos de comandos porque no crean un proceso adicional cada vez que hay que ejecutarlos.</p>
<p>Los <em>cmdlets</em> son sencillos de identificar porque se nombran siguiendo la convención <em>Verbo-Sustantivo</em>. Por ejemplo, el comando <code>Get-ChildItem</code> usa el verbo <code>Get</code> seguido por el nombre <code>ChildItem</code>. Cuando se ejecuta, lista el contenido de una o varias rutas, de forma similar a como funciona el comando <code>ls</code> en Bash.</p>
<pre><code class="lang-powershell"><span class="hljs-built_in">Get-ChildItem</span> <span class="hljs-literal">-Path</span> C:\Users
</code></pre>
<p>Esta convención puede hacer que los comandos sean más largos en comparación a sus equivalentes en Bash, lo que puede no ser demasiado cómodo al trabajar con PowerShell de forma interactiva. Sin embargo, el objetivo de hacerlo así es que sean sencillos de recordar y de hacer los scripts más legibles y autoexplicativos, lo que puede facilitar la compresión y el mantenimiento del código.</p>
<p>Los <em>cmdlets</em> suelen ser pequeños, en el sentido de que realizan una única función o tarea específica, en línea con la filosofía de los comandos en Unix “hacer una cosa y hacerla bien”. Como hemos comentado, cada <em>cmdlet</em> puede aceptar objetos como entrada y producirlos como salida, lo que permite encadenar varios <em>cmdlets</em> juntos para realizar operaciones complejas en un solo comando.</p>
<p>Como los <em>cmdlets</em> se implementan en el <em>framework</em> .NET, tienen un acceso muy sencillo a las API del sistema, así como a las de servicios y aplicaciones instalados. Por tanto, resulta fácil crear <em>cmdlets</em> que hagan de interfaz de línea de comandos de esas API, con el objeto de facilitar la creación de scripts con los que automatizar todo tipo de tareas.</p>
<p>Por ejemplo, los módulos de PowerShell <code>AzureAD</code> y <code>MSOnline</code> ofrecen un conjunto de <em>cmdlets</em> con los que se pueden automatizar tareas o gestionar desde la <em>shell</em> tanto Azure Active Directory como Office 365<sup id="2"><a class="post-section-overview" href="#fn2">2</a></sup>.</p>
<p>Volviendo al comando <code>Get-ChildItem</code>, gracias al uso de las distintas API del sistema, no solo sirve para listar el contenido de directorios, como <code>ls</code> en Bash, sino que también permite listar el contenido del almacén de certificados o del registro del sistema —donde Windows guardar su configuración—:</p>
<pre><code class="lang-powershell"><span class="hljs-built_in">Get-ChildItem</span> <span class="hljs-literal">-Path</span> HKLM:\SOFTWARE
</code></pre>
<h1 id="heading-como-lenguajes-de-scripting">Como lenguajes de scripting</h1>
<p>Los sistemas Unix surgieron en una época anterior al predominio de las interfaces gráficas de usuario. En ese contexto, las <em>shells</em> como Bash fueron diseñadas para ser la interfaz principal de los usuarios, por lo que, necesitan proporcionar un conjunto de herramientas y comandos muy generales para resolver una gran cantidad de tareas diferentes. Asimismo, la eficiencia en la escritura y ejecución de comandos es fundamental, por lo que con frecuencia se usan nombres cortos para comandos y opciones.</p>
<p>Por el contrario, en Windows se espera que la mayoría de las interacciones de los usuarios con el sistema se realicen a través de la interfaz gráfica, en lugar de una línea de comandos. PowerShell no se diseñó para ser una interfaz alternativa a la interfaz gráfica, sino como una herramienta para facilitar la automatización de tareas y la administración de sistemas a los usuarios más avanzados. Por eso, PowerShell trae una serie de <em>cmdlets</em> que facilitan la administración y el mantenimiento de sistemas Windows y estos siguen una convención de nombres que facilita la legibilidad y el mantenimiento de los scripts. Sin embargo, esto da como resultado una sintaxis más verbosa, al menos para quiénes están acostumbrados a utilizar Bash y otras <em>shells</em> similares.</p>
<p>Otra diferencia importante entre ambas <em>shell</em> aparece en la forma en la que se procesan los comandos.</p>
<p>Bash es un intérprete de línea de comandos tradicional, que se puede decir que funciona de manera lineal. Es decir, cuando se introduce un comando, realiza sobre la línea múltiples expansiones en un orden específico —expansión de variables, sustitución de comandos, división de palabras o expansión de nombres de archivos— que van sustituyendo distintas partes del comando.</p>
<p>En este proceso, no se tienen en cuenta ningún tipo de contexto. Por ejemplo, si se usan comodines —como en la expresión <code>A*.txt</code>— la expansión ocurrirá tanto si se ha puesto en el nombre del comando como si es en alguno de los argumentos. Si fuera este último caso, la <em>shell</em> no tiene en cuenta si en ese argumento se espera un nombre de archivo u otra cosa. La expansión ocurrirá siempre, con tal que exista algún archivo que encaje en la expresión.</p>
<p>Al final, tras todas las expansiones, lo que obtiene Bash es una lista de palabras de la que extrae el nombre del comando y sus argumentos para ejecutarlo.</p>
<p>El resultado es que, cuando se utiliza Bash como lenguaje de scripts, resulta ser un poco diferente a otros lenguajes de programación. Esto no significa que Bash no se use como lenguaje para desarrollar scripts para la administración del sistema, porque obviamente todo sistema Unix/Linux tiene muchos scripts en Bash. Pero cuando los scripts adquieren algo de complejidad, muchos administradores y desarrolladores prefieren utilizar otros lenguajes más convencionales, como Python.</p>
<p>PowerShell, por otro lado, tiene un enfoque más similar a la de un lenguaje de programación tradicional que a la de una shell de línea de comandos estilo Unix. En lugar de interpretar de forma lineal, sustituyendo sucesivamente distintas partes, el lenguaje PowerShell tiene una gramática bien definida. Como en cualquier lenguaje moderno, el intérprete toqueniza, analiza, construye el árbol de sintaxis abstracta (AST) del comando y finalmente evalúa el AST para ejecutar el comando. Es durante la evaluación de los elementos del comando, cuando se realizan todas las expansiones necesarias, como la expansión de variables, la sustitución de comandos o la expansión de nombres de archivos. Para hacer estas expansiones, PowerShell tiene en cuenta el contexto.</p>
<p>Por ejemplo, en Bash el siguiente comando imprime todos los archivos que empiezan por A y terminan por ‘.txt’ en el directorio actual:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">echo</span> A*.txt
</code></pre>
<p>El comando <code>echo</code> sirve para imprimir una cadena por la salida estándar, pero Bash hará la expansión de nombres de archivo y luego llamará a <code>echo</code> con todos esos archivos como argumentos del comando.</p>
<p>Sin embargo, en PowerShell ese mismo comando solo imprime <code>A*txt</code> porque <code>echo</code> —un alias de <code>Write-Output</code>— espera como argumento una cadena de caracteres, no un nombre de archivo. Por tanto, no hay ningún motivo para que PowerShell aplique la expansión de nombres de archivo, transformando la cadena.</p>
<p>Ambos lenguajes de scripts ofrecen construcciones comunes en cualquier lenguaje de programación, como bucles o condicionales. Sin embargo, el enfoque basado en objetos de PowerShell favorece el uso de tuberías para resolver problemas mediante la combinación de <em>cmdlets</em>, antes que usar dichas construcciones.</p>
<h1 id="heading-comandos-y-equivalencias">Comandos y equivalencias</h1>
<p>La siguiente tabla contiene una lista de los comandos más utilizados en Bash, junto con sus equivalentes en PowerShell y sus alias en esta <em>shell</em>.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>En Bash</td><td>En PowerShell</td><td>Alias en PowerShell</td><td>Descripción</td></tr>
</thead>
<tbody>
<tr>
<td><code>ls</code></td><td><a target="_blank" href="https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/get-childitem">Get-ChildItem</a></td><td><code>gci</code>, <code>dir</code>, <code>ls</code></td><td>Listar los elementos en un directorio.</td></tr>
<tr>
<td><code>cd</code></td><td><a target="_blank" href="https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/set-location">Set-Location</a></td><td><code>cd</code>, <code>chdir</code>, <code>sl</code></td><td>Cambiar el directorio actual.</td></tr>
<tr>
<td><code>pwd</code></td><td><a target="_blank" href="https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/get-location">Get-Location</a></td><td><code>pwd</code>, <code>gl</code></td><td>Mostrar la ruta del directorio actual.</td></tr>
<tr>
<td><code>man</code></td><td><a target="_blank" href="https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/get-help">Get-Help</a></td><td><code>man</code>, <code>help</code></td><td>Mostrar la ayuda de un comando.</td></tr>
<tr>
<td><code>cp</code></td><td><a target="_blank" href="https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/copy-item">Copy-Item</a></td><td><code>cp</code>, <code>copy</code>, <code>cpi</code></td><td>Copiar un elemento de un lugar a otro.</td></tr>
<tr>
<td><code>mv</code></td><td><a target="_blank" href="https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/move-item">Move-Item</a></td><td><code>mv</code>, <code>move</code>, <code>mi</code></td><td>Mover un elemento de un lugar a otro.</td></tr>
<tr>
<td><code>rm</code></td><td><a target="_blank" href="https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/remove-item">Remove-Item</a></td><td><code>rm</code>, <code>rmdir</code>, <code>del</code>, <code>erase</code>, <code>ri</code></td><td>Eliminar uno o más elementos.</td></tr>
<tr>
<td><code>cat</code></td><td><a target="_blank" href="https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/get-content">Get-Content</a></td><td><code>cat</code>, <code>type</code>, <code>gc</code></td><td>Mostrar el contenido de un archivo.</td></tr>
<tr>
<td><code>echo</code></td><td><a target="_blank" href="https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/write-output">Write-Output</a></td><td><code>echo</code>, <code>write</code></td><td>Escribir la salida a la consola.</td></tr>
<tr>
<td><code>find</code></td><td><a target="_blank" href="https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/get-childitem">Get-ChildItem</a> -Recurse     | <a target="_blank" href="https://learn.microsoft.com/es-es/powershell/module/microsoft.powershell.core/where-object">Where-Object</a></td><td>gci -r | ?</td><td>Buscar archivos en un directorio.</td></tr>
<tr>
<td><code>grep</code></td><td><a target="_blank" href="https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/select-string">Select-String</a></td><td><code>sls</code></td><td>Filtrar contenidos de un archivo según un patrón.</td></tr>
<tr>
<td><code>ps</code></td><td><a target="_blank" href="https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/get-process">Get-Process</a></td><td><code>gps</code>, <code>ps</code></td><td>Mostrar información sobre los procesos en ejecución.</td></tr>
<tr>
<td><code>kill</code></td><td><a target="_blank" href="https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/stop-process">Stop-Process</a></td><td><code>spps</code>, <code>kill</code></td><td>Detener un proceso en ejecución.</td></tr>
</tbody>
</table>
</div><p>Como se puede observar, muchos de los comandos de PowerShell en el listado tienen un alias con el nombre del comando equivalente en Bash. Sin embargo, es importante tener en cuenta que, aunque estos comandos son equivalentes en términos de funcionalidad, pueden comportarse de manera ligeramente diferente o requerir diferentes parámetros dependiendo del comando y del sistema operativo.</p>
<hr />
<ol>
<li><p><span id="fn1"></span>"Is PowerShell ready to replace my Cygwin shell on Windows?". Stack Overflow. Accedido el 9 de junio de 2023. https://stackoverflow.com/questions/573623/is-powershell-ready-to-replace-my-cygwin-shell-on-windows/573861#573861 <a class="post-section-overview" href="#1">↩</a></p>
</li>
<li><p><span id="fn2"></span>"Manage Microsoft 365 with Microsoft 365 PowerShell". Microsoft Learn. Accedido el 9 de junio de 2023. https://learn.microsoft.com/en-us/microsoft-365/enterprise/manage-microsoft-365-with-microsoft-365-powershell?view=o365-worldwide <a class="post-section-overview" href="#2">↩</a></p>
</li>
</ol>
<hr />
]]></content:encoded></item><item><title><![CDATA[PowerShell vs. Bash for Linux Users]]></title><description><![CDATA[If you prefer read the Spanish version, it is available here.

Current Windows systems allow the use of the Bash shell thanks to the Windows Subsystem for Linux (WSL). If we are regular Linux users and, for some reason, we are forced to use Windows, ...]]></description><link>https://jesustorres.es/powershell-vs-bash-for-linux-users</link><guid isPermaLink="true">https://jesustorres.es/powershell-vs-bash-for-linux-users</guid><category><![CDATA[Bash]]></category><category><![CDATA[Powershell]]></category><dc:creator><![CDATA[Jesús Torres]]></dc:creator><pubDate>Sun, 11 Jun 2023 10:33:08 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1686324587003/a32abf03-2d07-4ef3-895c-005d5dc4ded9.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you prefer read the Spanish version, it is available <a target="_blank" href="/powershell-vs-bash-para-usuarios-de-linux">here</a>.</p>
<hr />
<p>Current Windows systems allow the use of the Bash shell thanks to the Windows Subsystem for Linux (WSL). If we are regular Linux users and, for some reason, we are forced to use Windows, WSL offers us an easy way to use a command interface and tools that we know well and with which, surely, we feel much more comfortable than with the native ones from Windows.</p>
<p>However, when managing Windows systems, resorting to Linux ecosystem tools is usually not the best option because they present some limitations when used outside their original environment.</p>
<p>In this article, we will discuss the basic differences between PowerShell and Bash, and how these differences are conditioned by the characteristics of the ecosystem for which they were designed.</p>
<h1 id="heading-before-powershell">Before PowerShell</h1>
<p>Until very recently, the default command line interface for Windows was the <strong>Command Prompt</strong>.</p>
<p>This was the original command line interface of Windows and has its roots in the old MS-DOS operating system. MS-DOS was a text-based operating system, developed for early PCs and popular in the 80s and early 90s, before graphical user interfaces became common.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1686324196389/990194ad-4be1-4fb5-a8b6-cbaeced3533c.png" alt="MS-DOS 6 inteface executing the dir command." class="image--center mx-auto" /></td></tr>
</thead>
<tbody>
<tr>
<td>MS-DOS 6 inteface executing the <code>dir</code> command.</td></tr>
</tbody>
</table>
</div><p>One of the components of MS-DOS (and other versions of DOS) was the <code>COMMAND.COM</code> program, which ran at the end of system boot and implemented the command line interface. This interface and its scripting language (known as (.BAT) batch files) were very limited, compared to Unix/Linux shells, like Bash, mainly because of the limitations of the system itself and the hardware on which it was to run.</p>
<p>When Microsoft introduced Windows, it initially ran as a graphical user interface over MS-DOS. Over time, Windows evolved to become an independent operating system and introduced a new command line interface identified as the <strong>Command Prompt</strong>. This interface was implemented by the <code>cmd.exe</code> program, but its features were very similar to the old MS-DOS interface.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1686324208254/f80c4791-c11a-4256-9b2e-c5e7a63d13d8.png" alt="Command Prompt icon in Windows NT 3.1 with the MS-DOS logo." class="image--center mx-auto" /></td></tr>
</thead>
<tbody>
<tr>
<td><em>Command Prompt</em> icon in Windows NT 3.1 with the MS-DOS logo.</td></tr>
</tbody>
</table>
</div><p>In addition, <code>cmd.exe</code> is closely linked to the architecture of the Windows operating system and cannot be easily ported to other operating systems. This means that scripts and commands that work on <code>cmd.exe</code> often don't work on other operating systems without significant modifications.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1686324221105/e7fc77fe-1b06-436c-9598-7ec829ee8c8a.png" alt="Command Prompt of Windows 10." class="image--center mx-auto" /></td></tr>
</thead>
<tbody>
<tr>
<td>Command Prompt of Windows 10.</td></tr>
</tbody>
</table>
</div><p>PowerShell was introduced by Microsoft in 2006 to address many of these limitations. PowerShell is a much more powerful shell and scripting language than <code>cmd.exe</code>, with support for object-based scripting and a set of features that is comparable to Unix/Linux shells. PowerShell has also been ported to other operating systems, including Linux and macOS.</p>
<p>Although <code>cmd.exe</code> is still available in modern versions of Windows (and it is still possible to run .BAT files) PowerShell has become the default shell of the system and is usually the preferred one for many system administration-related tasks.</p>
<h1 id="heading-why-powershell">Why PowerShell?</h1>
<p>Since the early versions of Windows, Microsoft has always had a predilection for developing Graphical User Interfaces (GUIs). This is not only evident in the evolution of Windows, but also in the development of many associated applications and technologies, such as most of the wizards and system configuration and management tools.</p>
<p>However, over time, they realized that GUIs, despite their accessibility and ease of use for most users, have significant limitations when it comes to managing systems and automating tasks, especially on a large scale. PowerShell was the answer to this need.</p>
<p>The original intention was to include in Windows a set of tools similar to those of Unix<sup id="1"><a class="post-section-overview" href="#fn1">1</a></sup>. However, this did not work as well as expected. The reason is that the Unix ecosystem is built around text files. In Unix/Linux, system core, services, and application configuration and information are available in the form of text files, so the multiple text processing tools that accompany Bash are effectively management tools.</p>
<p>However, Windows is an ecosystem built around APIs and binary objects (such as <a target="_blank" href="http://en.wikipedia.org/wiki/Component_Object_Model">COM</a>, <a target="_blank" href="https://en.wikipedia.org/wiki/Windows_Management_Instrumentation">WMI</a>, <a target="_blank" href="https://en.wikipedia.org/wiki/Active_Directory">Active Directory</a>, the System Registry, etc.) so the traditional Unix text processing tools can't help too much in system management. It is for this reason they developed PowerShell, aiming to get a tool comparable to Unix/Linux shells but in the Windows ecosystem.</p>
<h1 id="heading-character-strings-vs-objects">Character Strings vs. Objects</h1>
<p>In Bash and other Unix/Linux shells, most operations are performed on character strings. The output of a command, through its standard output, is a string of characters, which can be redirected to a file or another command using the '&gt;' and '|' operators, respectively. Similarly, commands can accept a string of characters through their standard input, which can come from a file or the output of another command using the '&lt;' and '|' operators, respectively. And the variables used in scripts store and substitute as character strings.</p>
<p>For example, the following command can be used to list and filter processes:</p>
<pre><code class="lang-bash">ps aux | grep python
</code></pre>
<p>The <code>ps aux</code> command generates a detailed listing of all running processes, with a line of information for each process. The output of the command returns this information as a string of characters. The <code>grep python</code> command filters this text to display only the lines that contain the word "python". If this word appears in the command name, it is likely a Python language interpreter execution.</p>
<p>The <code>grep python</code> command does not search for the word in a specific property of the process but in the entire line containing its information. If, for example, we are only interested in listing the processes of the user “python” or the processes of the “python” command, we would need to find another solution.</p>
<p>In contrast, PowerShell handles the connection between commands differently. Instead of passing character strings, PowerShell can pass complete objects (in fact, they are .NET objects) where each one is an entity with properties and methods. This allows commands that are chained in a PowerShell pipeline using the '|' operator to be more aware of the structure and content of the information they receive.</p>
<p>For example, consider the PowerShell equivalent command of the previously mentioned Bash command:</p>
<pre><code class="lang-powershell"><span class="hljs-built_in">Get-Process</span> | <span class="hljs-built_in">Where-Object</span> { <span class="hljs-variable">$_</span>.ProcessName <span class="hljs-operator">-like</span> <span class="hljs-string">"*python*"</span> }
</code></pre>
<p>The <code>Get-Process</code> command generates a list of process objects, each of which has properties such as <code>ProcessName</code>, <code>Id</code>, etc. The <code>Where-Object</code> command iterates over the objects evaluating the indicated condition, to filter them based on their properties; instead of searching for the text "python" in an unstructured string of characters, like <code>grep</code> does. Specifically, in the previous example, <code>Where-Object</code> extracts the value of the <code>ProcessName</code> property of the current object and checks if it contains the substring "python". That is, it is easy to check conditions in any of the properties of each process listed returned by <code>Get-Process</code>.</p>
<p>Although it may seem so, the result of <code>Where-Object</code> is not text, but a list of objects that meet the indicated condition. Since the output of <code>Where-Object</code> will not be stored in a variable nor used with another command, the PowerShell interpreter converts it into text to display it to the user in the console.</p>
<p>Obviously, PowerShell can process texts like Bash does. It has its own tools, which accept and return character strings, in addition to being able to invoke the typical tools of Unix systems, if they are available on the system.</p>
<p>In both Unix/Linux and Windows, any process can have a standard input and output, being the mechanism by which shells (including Bash and PowerShell) can connect the text output of a command with the input of another. The difference is that, in PowerShell, additionally, functions and cmdlets allow implementing commands that receive and return objects, instead of just character strings.</p>
<p>In PowerShell, both worlds can be easily combined. For example, suppose we have a list of books in a text file <code>books.json</code> in JSON format.</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"books"</span>: [
        {<span class="hljs-attr">"title"</span>: <span class="hljs-string">"1984"</span>, <span class="hljs-attr">"author"</span>: <span class="hljs-string">"George Orwell"</span>, <span class="hljs-attr">"year"</span>: <span class="hljs-number">1949</span>},
        {<span class="hljs-attr">"title"</span>: <span class="hljs-string">"Brave New World"</span>, <span class="hljs-attr">"author"</span>: <span class="hljs-string">"Aldous Huxley"</span>, <span class="hljs-attr">"year"</span>: <span class="hljs-number">1932</span>},
        {<span class="hljs-attr">"title"</span>: <span class="hljs-string">"Fahrenheit 451"</span>, <span class="hljs-attr">"author"</span>: <span class="hljs-string">"Ray Bradbury"</span>, <span class="hljs-attr">"year"</span>: <span class="hljs-number">1953</span>}
    ]
}
</code></pre>
<p>Filtering books according to some criteria and selecting various properties from this listing, using only text processing tools, can be very complex. However, we can convert the content of the file into lists of objects, to easily iterate over them, filter, and select the information we want to show to the user.</p>
<pre><code class="lang-powershell">(<span class="hljs-built_in">Get-Content</span> books.json | <span class="hljs-built_in">ConvertFrom-Json</span>).books |
    <span class="hljs-built_in">Where-Object</span> { <span class="hljs-variable">$_</span>.year <span class="hljs-operator">-lt</span> <span class="hljs-number">1950</span> } | <span class="hljs-built_in">ForEach-Object</span> { <span class="hljs-variable">$_</span>.title }
</code></pre>
<h1 id="heading-cmdlets-in-powershell">Cmdlets in PowerShell</h1>
<p>Cmdlets (pronounced as <em>command-let</em>) are a type of PowerShell command implemented through .NET classes (inheriting from the <code>System.Management.Automation.Cmdlet</code> class). They are usually written in a language like C# and compiled into .DLL files, which PowerShell loads to execute the command within the context of the current interpreter or script. Therefore, they are lighter than other types of commands because they do not create an additional process every time they need to be executed.</p>
<p>Cmdlets are easy to identify because they are named following the "Verb-Noun" convention. For example, the <code>Get-ChildItem</code> command uses the verb <code>Get</code> followed by the noun <code>ChildItem</code>. When executed, it lists the contents of one or more paths, similarly to how the <code>ls</code> command works in Bash.</p>
<pre><code class="lang-powershell"><span class="hljs-built_in">Get-ChildItem</span> <span class="hljs-literal">-Path</span> C:\Users
</code></pre>
<p>This convention can make the commands longer compared to their equivalents in Bash, which may not be very comfortable when working with PowerShell interactively. However, the aim is to make them easy to remember and make scripts more readable and self-explanatory, which can facilitate understanding and code maintenance.</p>
<p>Cmdlets are typically small, in the sense that they perform a single specific function or task, in line with the philosophy of Unix commands to "do one thing and do it well". As we have mentioned, each cmdlet can accept objects as input and produce them as output, allowing several cmdlets to be chained together to perform complex operations in a single command.</p>
<p>Since cmdlets are implemented in the .NET framework, they have very easy access to system APIs, as well as to services and installed applications. Therefore, it is easy to create cmdlets that act as command line interfaces for these APIs, in order to facilitate the creation of scripts to automate all kinds of tasks.</p>
<p>For example, the PowerShell <code>AzureAD</code> and <code>MSOnline</code> modules offer a set of cmdlets that can be used to automate tasks or manage both Azure Active Directory and Office 365 from the shell<sup id="2"><a class="post-section-overview" href="#fn2">2</a></sup>.</p>
<p>Returning to the <code>Get-ChildItem</code> command, thanks to the use of various system APIs, it not only serves to list directory contents, like <code>ls</code> in Bash, but also allows listing the contents of the certificate store or the system registry (where Windows saves its configuration):</p>
<pre><code class="lang-powershell"><span class="hljs-built_in">Get-ChildItem</span> <span class="hljs-literal">-Path</span> HKLM:\SOFTWARE
</code></pre>
<h1 id="heading-as-scripting-languages">As Scripting Languages</h1>
<p>Unix systems emerged in an era before the dominance of graphical user interfaces. In this context, shells like Bash were designed to be the primary interface for users, so they need to provide a very general set of tools and commands to solve a wide range of different tasks. Likewise, efficiency in writing and executing commands is essential, so short names for commands and options are often used.</p>
<p>In contrast, on Windows, it is expected that most of the user interactions with the system will be performed through the graphical interface, rather than a command line. PowerShell was not designed to be an alternative interface to the graphical one, but rather as a tool to facilitate task automation and system administration for more advanced users. Therefore, PowerShell comes with a series of cmdlets that simplify the administration and maintenance of Windows systems and these follow a naming convention that facilitates script readability and maintenance. However, this results in a more verbose syntax, at least for those accustomed to using Bash and other similar shells.</p>
<p>Another significant difference between both shells appears in the way commands are processed.</p>
<p>Bash is a traditional command-line interpreter, which can be said to operate linearly. That is, when a command is entered, it performs multiple expansions on the line in a specific order (variable expansion, command substitution, word splitting, or filename expansion) which replace different parts of the command.</p>
<p>In this process, no context is taken into account. For example, if wildcards are used — as in the expression <code>A*.txt</code> — the expansion will occur whether it has been put in the command name or in any of the arguments. If it is the latter case, the shell does not take into account whether a filename or something else is expected in that argument. The expansion will always occur, as long as there is any file that fits the expression.</p>
<p>In the end, after all the expansions, what Bash gets is a list of words from which it extracts the command name and its arguments to execute it.</p>
<p>The result is that, when using Bash as a scripting language, it turns out to be somewhat different from other programming languages. This does not mean that Bash is not used as a language to develop scripts for system administration, because obviously, every Unix/Linux system has many Bash scripts. But when scripts gain some complexity, many administrators and developers prefer to use more conventional languages, such as Python.</p>
<p>PowerShell, on the other hand, takes an approach more similar to that of a traditional programming language than a Unix-style command-line shell. Instead of interpreting linearly, successively substituting different parts, the PowerShell language has a well-defined grammar. As in any modern language, the interpreter tokenizes, parses, constructs the abstract syntax tree (AST) of the command, and finally evaluates the AST to execute the command. It is during the evaluation of the command elements, when all the necessary expansions are made, such as variable expansion, command substitution, or filename expansion. To make these expansions, PowerShell takes the context into account.</p>
<p>For example, in Bash, the following command prints all files that start with A and end with '.txt' in the current directory:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">echo</span> A*.txt
</code></pre>
<p>The <code>echo</code> command is used to print a string to standard output, but Bash will do the filename expansion and then call <code>echo</code> with all those files as command arguments.</p>
<p>However, in PowerShell, that same command only prints <code>A*txt</code> because <code>echo</code> —an alias for <code>Write-Output</code>— expects a string of characters as an argument, not a filename. Therefore, there is no reason for PowerShell to apply filename expansion, transforming the string.</p>
<p>Both scripting languages offer common constructs in any programming language, such as loops or conditionals. However, PowerShell's object-based approach favors the use of pipes to solve problems by combining cmdlets, rather than using these constructs.</p>
<h1 id="heading-commands-and-equivalences">Commands and Equivalences</h1>
<p>The following table contains a list of the most commonly used commands in Bash, along with their equivalents in PowerShell and their aliases in this shell.</p>
<p>Sure, here's the translated content:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>In Bash</td><td>In PowerShell</td><td>Alias in PowerShell</td><td>Description</td></tr>
</thead>
<tbody>
<tr>
<td><code>ls</code></td><td><a target="_blank" href="https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/get-childitem">Get-ChildItem</a></td><td><code>gci</code>, <code>dir</code>, <code>ls</code></td><td>List the items in a directory.</td></tr>
<tr>
<td><code>cd</code></td><td><a target="_blank" href="https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/set-location">Set-Location</a></td><td><code>cd</code>, <code>chdir</code>, <code>sl</code></td><td>Change the current directory.</td></tr>
<tr>
<td><code>pwd</code></td><td><a target="_blank" href="https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/get-location">Get-Location</a></td><td><code>pwd</code>, <code>gl</code></td><td>Show the path of the current directory.</td></tr>
<tr>
<td><code>man</code></td><td><a target="_blank" href="https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/get-help">Get-Help</a></td><td><code>man</code>, <code>help</code></td><td>Show the help of a command.</td></tr>
<tr>
<td><code>cp</code></td><td><a target="_blank" href="https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/copy-item">Copy-Item</a></td><td><code>cp</code>, <code>copy</code>, <code>cpi</code></td><td>Copy an item from one place to another.</td></tr>
<tr>
<td><code>mv</code></td><td><a target="_blank" href="https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/move-item">Move-Item</a></td><td><code>mv</code>, <code>move</code>, <code>mi</code></td><td>Move an item from one place to another.</td></tr>
<tr>
<td><code>rm</code></td><td><a target="_blank" href="https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/remove-item">Remove-Item</a></td><td><code>rm</code>, <code>rmdir</code>, <code>del</code>, <code>erase</code>, <code>ri</code></td><td>Remove one or more items.</td></tr>
<tr>
<td><code>cat</code></td><td><a target="_blank" href="https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/get-content">Get-Content</a></td><td><code>cat</code>, <code>type</code>, <code>gc</code></td><td>Show the content of a file.</td></tr>
<tr>
<td><code>echo</code></td><td><a target="_blank" href="https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/write-output">Write-Output</a></td><td><code>echo</code>, <code>write</code></td><td>Write the output to the console.</td></tr>
<tr>
<td><code>find</code></td><td><a target="_blank" href="https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/get-childitem">Get-ChildItem</a> -Recurse     | <a target="_blank" href="https://learn.microsoft.com/es-es/powershell/module/microsoft.powershell.core/where-object">Where-Object</a></td><td>gci -r | ?</td><td>Search files in a directory.</td></tr>
<tr>
<td><code>grep</code></td><td><a target="_blank" href="https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/select-string">Select-String</a></td><td><code>sls</code></td><td>Filter contents of a file according to a pattern.</td></tr>
<tr>
<td><code>ps</code></td><td><a target="_blank" href="https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/get-process">Get-Process</a></td><td><code>gps</code>, <code>ps</code></td><td>Show information about running processes.</td></tr>
<tr>
<td><code>kill</code></td><td><a target="_blank" href="https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/stop-process">Stop-Process</a></td><td><code>spps</code>, <code>kill</code></td><td>Stop a running process.</td></tr>
</tbody>
</table>
</div><p>As can be seen, many of the PowerShell commands in the list have an alias with the name of the equivalent command in Bash. However, it's important to note that, while these commands are equivalent in terms of functionality, they may behave slightly differently or require different parameters depending on the command and the operating system.</p>
<hr />
<ol>
<li><p><span id="fn1"></span>"Is PowerShell ready to replace my Cygwin shell on Windows?". Stack Overflow. Accessed June 9, 2023. https://stackoverflow.com/questions/573623/is-powershell-ready-to-replace-my-cygwin-shell-on-windows/573861#573861 <a class="post-section-overview" href="#1">↩</a></p>
</li>
<li><p><span id="fn2"></span>"Manage Microsoft 365 with Microsoft 365 PowerShell". Microsoft Learn. Accessed June 9, 2023. https://learn.microsoft.com/en-us/microsoft-365/enterprise/manage-microsoft-365-with-microsoft-365-powershell?view=o365-worldwide <a class="post-section-overview" href="#2">↩</a></p>
</li>
</ol>
<hr />
]]></content:encoded></item><item><title><![CDATA[Píldoras sobre sistemas de productividad]]></title><description><![CDATA[Si has llegado hasta aquí, seguramente ya sepas que el pasado 2 de diciembre de 2021 tuve la oportunidad de impartir la conferencia "Como optimizar tu tiempo" en el VII Congreso de Estudiantes de Ingeniería Informática (CESINF) de la ULL.
Y que, como...]]></description><link>https://jesustorres.es/pildoras-sobre-sistemas-de-productividad-vii-cesinf</link><guid isPermaLink="true">https://jesustorres.es/pildoras-sobre-sistemas-de-productividad-vii-cesinf</guid><category><![CDATA[Productivity]]></category><category><![CDATA[GTD]]></category><category><![CDATA[notion]]></category><category><![CDATA[spanish]]></category><dc:creator><![CDATA[Jesús Torres]]></dc:creator><pubDate>Thu, 09 Dec 2021 00:22:06 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1638814933076/lvdu9xGlAi.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Si has llegado hasta aquí, seguramente ya sepas que el pasado 2 de diciembre de 2021 tuve la oportunidad de impartir la conferencia "Como optimizar tu tiempo" en el <a target="_blank" href="https://www.cesinfull.com/">VII Congreso de Estudiantes de Ingeniería Informática</a> (CESINF) de la ULL.
Y que, como no podía ser de otra manera en una conferencia sobre gestión del tiempo, no tuve tiempo suficiente para llegar hasta dónde quería 😅.</p>
<p>En todo caso, en una conferencia de 30 min. es normal tener que dejar en el tintero muchas cuestiones y, por tanto, que a los asistentes les falte información a la hora de poner algo de lo dicho en práctica.
Así que voy a intentar dejar por aquí algunas notas con lo más importante a tener en cuenta para adoptar un sistema de productividad y consejos para aprovechar mejor el tiempo que dedicamos a nuestras tareas.</p>
<h1 id="heading-presentacion-y-referencias">Presentación y referencias</h1>
<p>Esta es la presentación que utilice:</p>
<div class="hn-embed-widget" id="vii-cesinf-optimizacion-del-tiempo"></div><p>Las transparencias no tienen mucho texto, pero he incluido al final referencias a las fuentes oficiales de las técnicas comentadas —que en su mayor parte son libros— y enlaces a las aplicaciones recomendadas.
En todo caso, con solo buscar por el nombre en Internet encontraremos multitud de páginas y tutoriales que explican los principales detalles de cada una de estas técnicas.</p>
<p><em><strong>NOTA:</strong> Para el final de la presentación tenía preparada una pequeña encuesta para saber cuál de los sistemas de productividad parecía más interesan.</em>
<em>Si ves los siguientes vídeos y te animas indicar tu elección, puedes hacerlo <a target="_blank" href="https://www.menti.com/p8nbrmq7x3">aquí</a>.</em></p>
<h1 id="heading-en-que-consiste-gtd-en-trello">En qué consiste GTD (en Trello)</h1>
<p>Para quienes puedan estar interesados, he grabado esta píldora sobre qué es GTD y como aplicarlo usando <a target="_blank" href="https://trello.com">Trello</a>:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://youtu.be/5XRHn9oR9lM">https://youtu.be/5XRHn9oR9lM</a></div>
<p><em>⚠ El tablero completo se puede filtrar por etiqueta pulsando en <strong>"Filtrar"</strong> en el lado derecho del tablero o usando la tecla <kbd>F</kbd>.</em></p>
<p>El tablero, por si alguien quiere usarlo como base para el suyo, está disponible <a target="_blank" href="https://trello.com/b/61a89a15d454c887b749cc76">aquí</a>.
Incluye dos botones en las tarjetas para ordenar la lista <em>próximos</em> por urgencia o fecha de vencimiento y una tarjeta plantilla para proyectos.
Además, todos los días se ordena la lista de <em>próximos</em> por la etiqueta <em>urgencia</em>.</p>
<h1 id="heading-en-que-consiste-systemist-en-trello">En qué consiste Systemist (en Trello)</h1>
<p>También he grabado una píldora sobre <a target="_blank" href="https://todoist.com/productivity-methods/systemist">Systemist</a> usando <a target="_blank" href="https://trello.com">Trello</a>:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://youtu.be/8kC2WGS8Zrc">https://youtu.be/8kC2WGS8Zrc</a></div>
<p>El tablero está disponible <a target="_blank" href="https://trello.com/b/61a7d5d5c20c7319e468c47f">aquí</a>, con características muy similares al de <a target="_blank" href="https://trello.com/b/61a89a15d454c887b749cc76">GTD</a>.</p>
<h1 id="heading-gtd-en-notion">GTD en Notion</h1>
<p>Una de las cosas que más pena me dio fue no poder explicar como utilizo GTD con <a target="_blank" href="https://notion.so">Notion</a>.</p>
<p>La noche anterior recorté algunas partes de la presentación para asegurar que me daría tiempo.
Me parece una herramienta fantástica para montar un sistema de productividad personal —o un gestor de documental, de notas, de proyectos, de rectas de cocina o de lo que se nos ocurra—.</p>
<p>Como no puedo ser, he grabado esta píldora explicando los pasos para hacerlo:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://youtu.be/nkNVEC3kW0U">https://youtu.be/nkNVEC3kW0U</a></div>
<p><em>⚠ Al crear el dashboard final, las tablas también deben filtrarse por "Estado" para solo mostrar las que están en "Próximo".</em></p>
<p>En cualquier caso, no debemos olvidar que esto no son más que ideas.
Cada uno debe adaptarlo a sus necesidades.
Por ejemplo, así se ve actualmente mi <em>dashboard</em> y las vistas que uso en las bases de datos de tareas y proyectos:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1639143786336/J4fLjf9iM.png" alt="Screenshot_20211210_132750.png" /></p>
<h1 id="heading-consejos-finales">Consejos finales</h1>
<p>Para terminar, creo que es importante incidir en algunos consejos que también comenté durante la charla.</p>
<p>Lo primero es no solo es fundamental planificar las tareas de forma adecuada, mediante un sistema de productividad o alguna otra técnica más básica.
También debemos asegurarnos de disponer de tiempo de calidad para trabajar.
El tiempo de calidad se consigue <strong>evitando interrupciones</strong> y <strong>concentrándonos en una sola tarea al mismo tiempo</strong>.</p>
<p>Técnicas que nos pueden ayudar a maximizar el tiempo concentrados son el <strong>bloqueo de tiempo</strong> y el <strong>pomodoro</strong>.</p>
<p>Es aconsejable <strong>desactivar las notificaciones del móvil y del ordenador</strong> y <strong>no trabajar con el correo electrónico abierto</strong>. 
El correo lo podemos consultar en un par de momentos planificados del día, preferentemente nunca al comienzo de la jornada —cuándo estamos con más energía— y es interesante que los mensajes que requieran tiempo para ser procesados no interrumpan nuestro ritmo de trabajo. 
Es preferible incluirlos como tareas a realizar en nuestro gestor de tareas.</p>
<p>También <strong>es interesante capturar rápidamente cualquier idea, tarea o contenido</strong> que surja, para poder analizarlo posteriormente, sin interrumpir el trabajo que estamos efectuando.</p>
<p>Lo otro que tenemos que tener en cuenta es que <strong>es interesante tener tiempo sin hacer nada</strong>, fundamentalmente porque es algo muy positivo para la <strong>creatividad</strong>.
A veces nuestra rutina diaria nos ofrece ese tiempo, por ejemplo cuando vamos de camino a casa o al trabajo o cuando hacemos ejercicio.
Pero si no fuera así, deberíamos planificar esos huecos en nuestro sistema de productividad.</p>
]]></content:encoded></item><item><title><![CDATA[Escritorio virtual de Windows 10 (y II)]]></title><description><![CDATA[Vamos a ver algunos consejos para optimizar la máquina virtual creada en el artículo anterior. Este artículo pertenece a una serie donde se explica como instalar Windows 10 en una máquina virtual asignándole una de las GPU del equipo de forma exclusi...]]></description><link>https://jesustorres.es/escritorio-virtual-de-windows-10-parte-2</link><guid isPermaLink="true">https://jesustorres.es/escritorio-virtual-de-windows-10-parte-2</guid><category><![CDATA[desktop]]></category><category><![CDATA[Linux]]></category><category><![CDATA[Windows]]></category><category><![CDATA[spanish]]></category><dc:creator><![CDATA[Jesús Torres]]></dc:creator><pubDate>Sun, 14 Jun 2020 21:36:51 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/unsplash/dpbXgTh0Lac/upload/v1638552569300/KxfW0niDO.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>Vamos a ver algunos consejos para optimizar la máquina virtual creada en el</em> <a target="_blank" href="/escritorio-virtual-de-windows-10-parte-1"><em>artículo anterior</em></a><em>.</em> <em>Este artículo pertenece a una serie donde se explica como instalar Windows 10 en una máquina virtual asignándole una de las GPU del equipo de forma exclusiva, para obtener un rendimiento gráfico similar al que tendría en una máquina real.</em> <em>Si te has perdido algún artículo anterior de esta historia, el primero lo tienes</em> <a target="_blank" href="/iommu-primer-asalto"><em>aquí</em></a>.</p>
<hr />
<p>Una vez apagada la máquina virtual, si seleccionamos en el menú el icono con una exclamación —con el texto de ayuda <strong>Mostrar detalles del hardware virtual</strong>— podemos ver la configuración definitiva y ajustarla.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1637026439223/kYgQjJMfS.png" alt="Hardware de la máquina virtual tras la instalación" class="image--center mx-auto" /></p>
<p>Podemos quitar las unidades CDROM o, en todo caso, dejar solo una por lo que pueda surgir. También se puede quitar el dispositivo tipo <strong>Serial</strong> y añadir uno de tipo <strong>Tableta</strong>. La tableta nos permite evitar problemas con el posicionamiento del puntero y usar el ratón con la pantalla de la máquina virtual sin antes tener que hacer clic.</p>
<p>Si hemos dejado una unidad CDROM, podemos cambiar su <strong>Bus de disco</strong> a <strong>SCSI</strong>. Eso nos permite eliminar también los dispositivos <strong>Controller IDE</strong>.</p>
<h1 id="heading-rendimiento-del-almacenamiento">Rendimiento del almacenamiento</h1>
<p>En las <strong>Opciones de Rendimiento</strong> del <strong>SCSI Disco</strong> se puede indicar el <strong>Modo caché</strong> como <strong>none</strong> y el <strong>Modo E/S</strong> como <strong>native</strong>.</p>
<p>El primero evita que el anfitrión consuma memora cacheando las operaciones de E/S de la máquina virtual. Esto también lo hace el sistema operativo de la máquina virtual, por lo que no tiene sentido hacerlo dos veces. Quizás fuera útil si pensáramos lanzar varias máquinas virtuales que accedan al mismo tiempo a los mismos dispositivos de almacenamiento.</p>
<p>El segundo activa el uso de <a target="_blank" href="https://blog.cloudflare.com/io_submit-the-epoll-alternative-youve-never-heard-about/">llamadas al sistema nativas de Linux para la E/S asíncrona</a> al archivo con el contenido del disco duro virtual. El valor por defecto usa hilos y operaciones síncronas.</p>
<p>La combinación de estas dos opciones debería ofrecernos mejor rendimiento que las opciones por defecto.</p>
<p>Dentro de la máquina virtual, en el intérprete de comandos de Windows, es interesante ejecutar este comando:</p>
<pre><code class="lang-powershell">fsutil behavior query DisableDeleteNotify
</code></pre>
<p>Si devuelve 0, nos indica que cuando un bloque del almacenamiento deja de usarse, Windows envía al dispositivo el comando TRIM para indicarle que ha quedado libre.</p>
<p>Si estamos utilizando una imagen de disco en formato <strong>raw</strong>, esto no tendrá ningún efecto. Pero con <strong>qcow2</strong> el archivo reducirá su tamaño, al necesitar menos espacio para almacenar la imagen. Si empleamos un volumen lógico LVM sobre un dispositivo SSD, como es mi caso, el comando TRIM se propagará hasta el SSD, evitando la degradación del rendimiento del dispositivo.</p>
<p>Si hiciera falta, para activarlo hay que ejecutar:</p>
<pre><code class="lang-powershell">fsutil behavior <span class="hljs-built_in">set</span> DisableDeleteNotify <span class="hljs-number">0</span>
</code></pre>
<h1 id="heading-rendimiento-de-la-interfaz-de-red">Rendimiento de la interfaz de red</h1>
<p>La tarjeta de red de la máquina virtual es el dispositivo con el nombre <strong>NIC &lt;MAC&gt;</strong>. Por lo general se trata de una emulación de una tarjeta Intel e1000 o una <a target="_blank" href="https://es.wikipedia.org/wiki/Realtek">Realtek RTL8139</a>. Se puede obtener mejor rendimiento cambiando el <strong>Modelo de dispositivo</strong> a <strong>virtio</strong>, que es una interfaz de red paravirtualizada, como la que usamos con el disco duro virtual. Lo único es que es necesario iniciar la máquina virtual e instalar los controladores de la carpeta <code>NetKVM</code> de la ISO de controladores VirtIO.</p>
<p>Por defecto la interfaz de red de la máquina virtual está conectada a una red virtual llamada "default", en la que también está el equipo anfitrión. En esta red la máquina virtual recibe una IP privada y su acceso a Internet se realiza a través del anfitrión utilizando <a target="_blank" href="https://es.wikipedia.org/wiki/Traducci%C3%B3n_de_direcciones_de_red">NAT</a>.</p>
<p>Todo esto se puede simplificar mucho cambiando <strong>Fuente de red</strong> a <strong>Dispositivo anfitrión &lt;interfaz&gt;: macvtap</strong> y <strong>Modo de fuente</strong> a <strong>Puente</strong>. Usando <a target="_blank" href="https://virt.kernelnewbies.org/MacVTap">macvtap</a> la máquina virtual pasa a algo así como a compartir la la tarjeta de red "&lt;interfaz&gt;" del equipo anfitrión. La red le asignará a la máquina virtual una IP como si fuera una máquina real y de esta forma puede conectarse al resto de equipos de la red y a Internet sin usar al anfitrión como intermediario.</p>
<p>En mi caso, al utilizar <em>macvtap</em> en Ubuntu 16.04, la interfaz de red funcionaba en el primer arranque pero nunca en posteriores. Se debía a un conflicto con <em>NetworkManager</em>, que decidía por su cuenta bajar la interfaz <em>macvtap</em> anfitrión. Se resuelve editando el archivo <code>/etc/NetworkManager/NetworkManager.conf</code> para añadir lo siguiente:</p>
<pre><code class="lang-ini"><span class="hljs-section">[keyfile]</span>  
<span class="hljs-attr">unmanaged-devices</span>=interface-name:macvtap0
</code></pre>
<p>para que <em>NetworkManager</em> no intente gestionar esa interfaz. En Ubuntu 18.04, por el momento no he tenido ningún problema similar, de modo que no parece que haga falta este truco.</p>
<h1 id="heading-video-qxl">Vídeo QXL</h1>
<p>En el dispositivo <strong>Video Cirrus</strong> se puede cambiar el modelo a <strong>QXL</strong>. El modelo <strong>Video Cirrus</strong> emula una tarjeta gráfica VGA del fabricante Cirrus Logic. Mientras que QXL es un dispositivo de vídeo paravirtualizado, por lo que ofrece mejor rendimiento. Además, mientras que con la emulación VGA estamos limitados a una resolución 800x600, con QXL tenemos automáticamente 1024x768. Será necesario iniciar la máquina virtual e instalar los controladores de la carpeta <code>qxldod</code> de la ISO de controladores VirtIO.</p>
<h1 id="heading-asignacion-de-memoria-ram">Asignación de memoria RAM</h1>
<p>En la configuración de memoria podemos configurar cuánta memoria pensará la máquina virtual que tiene —la <strong>Asignación máxima</strong>— y cuanta memoria del anfitrión puede realmente usar como máximo —la <strong>Asignación actual</strong>—.</p>
<p>Por ejemplo, mi máquina virtual supone que tiene 8GB de RAM, pero el sistema anfitrión nunca le asignará más de 4 GB de memoria.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1637026439233/wjJfsFSO55.png" alt="Configuración de la asignación de memoria" class="image--center mx-auto" /></p>
<p>Desde el punto de vista del sistema operativo, la máquina virtual es un proceso más. Cuando se inicia, pide al sistema operativo la cantidad de memoria indicada en <strong>Asignación máxima</strong> como memoria RAM para la máquina. El sistema operativo le reserva el espacio de direcciones pero realmente solo le asigna la memoria según va a accediendo a ella. Es decir, que la memoria se asigna a la máquina virtual a demanda.</p>
<p>Si miramos el hardware detectado por nuestro sistema operativo, seguramente observaremos un dispositivo desconocido que se corresponde con el dispositivo balón de memoria —en inglés, <em>balloon device</em>—. Para que funcione adecuadamente es necesario instalar en la máquina virtual el controlador <code>balloon</code> de la ISO de controladores VirtIO.</p>
<p>Con el controlador del balón de memoria instalado, cuando el sistema operativo arranca, dicho controlador reserva una porción de la memoria de la máquina para que nunca pueda usarse. ¿Cuánta memoria reserva?. La necesaria para que el sistema nunca pueda utilizar más memoria que la cantidad indicada en <strong>Asignación actual</strong>.</p>
<p>Es decir, que la máquina virtual piensa que la memoria instalada es <strong>Asignación máxima</strong>, pero nunca podrá emplear más de <strong>Asignación actual</strong> de la memoria del sistema anfitrión.</p>
<p>La cantidad indicada en "Asignación actual" se puede cambiar en tiempo de ejecución desde el anfitrión mediante el comando <code>virsh</code>:</p>
<pre><code class="lang-sh">sudo virsh setmem &lt;máquina_virtual&gt; 2G --live
</code></pre>
<p>Si el nuevo valor es mayor, el balón se encogerá para que el sistema de la máquina virtual pueda consumir más memoria. Obviamente, nunca podremos asignar un valor superior a <strong>Asignación actual</strong>.</p>
<p>Por el contrario, si el nuevo valor es menor, el balón crecerá y devolverá la memoria adicional que reserve al sistema anfitrión, haciendo que haya menos memoria para la máquina virtual.</p>
<p>Si no nos interesa este comportamiento, basta con que no instalemos el controlador del balón de memoria. O que pongamos en <strong>Asignación máxima</strong> y en <strong>Asignación actual</strong> la misma cantidad. Sin embargo, hay que tener presente que durante el arranque, Windows pone a ceros toda la memoria de la máquina, haciendo que el sistema anfitrión tenga que asignarle efectivamente la memoria indicada en "Asignación máxima". El controlador del balón de memoria nos permite obligar después a Windows a devolver buena parte de la memoria, hasta lo indicado en <strong>Asignación actual</strong>.</p>
<h1 id="heading-espacio-de-intercambio-en-la-maquina-virtual">Espacio de intercambio en la máquina virtual</h1>
<p>En algunos foros se sugiere desactivar el espacio de intercambio —o <em>swap</em>—  en el sistema operativo de la máquina virtual. La justificación es que el sistema anfitrión ya tiene su espacio de intercambio donde pueda intercambiar cualquier porción de la memoria, incluida la asignada a las máquinas virtuales.</p>
<p>Pero lo cierto es que nadie mejor que el sistema operativo de la máquina virtual para saber qué partes intercambiar primero, por lo que es mejor que tenga su propio espacio de intercambio.</p>
<p>Al reducir la cantidad de memoria disponible con el <em>balloon device</em>, obligamos al sistema operativo de la máquina virtual a decidir qué partes de la memoria son menos importantes respecto al rendimiento, para liberarlas o intercambiarlas primero.</p>
<h1 id="heading-kernal-samepage-merging-ksm">Kernal SamePage Merging (KSM)</h1>
<p>En algunos foros se recomienda activar <a target="_blank" href="https://en.wikipedia.org/wiki/Kernel_same-page_merging">KSM</a> en el sistema Linux anfitrión. KSM es una tecnología creada originalmente para intentar maximizar el número de máquinas virtuales en un mismo equipo. Básicamente, consiste en un hilo del núcleo que recorre la memoria buscando regiones con el mismo contenido. Cuando las encuentra, ahorra memoria liberando los duplicados y quedándose solo con una copia.</p>
<p>Por tanto, parece una tecnología interesante para evitar que las máquinas virtuales con Windows acaparen demasiada memoria cuando la llenan de ceros durante el arranque. De hecho <a target="_blank" href="https://kernelnewbies.org/Linux_2_6_32#Kernel_Samepage_Merging_.28memory_deduplication.29">Red Hat hizo un experimento</a> donde pudo lanzar hasta 52 Windows con 1 GB en un servidor con solamente 16 GB.</p>
<p>Sin embargo, hay que tener presente que recorrer la memoria de esta manera no es gratis. KSM sacrifica tiempo de CPU para maximizar el número de máquinas virtuales. Por eso yo no he activado y probado KSM, hasta el momento.</p>
<h1 id="heading-afinidad-de-los-procesadores">Afinidad de los procesadores</h1>
<p>Las CPU de la máquina virtual se implementan como hilos de ejecución en el anfitrión. Para mejorar el rendimiento se puede vincular cada uno de esos hilos a una CPU real, evitando que migren de CPU a criterio del sistema, lo que dificulta aprovechar adecuadamente las memorias caché.</p>
<p>Lamentablemente, para configurar esta funcionalidad no podemos usar la interfaz gráfica de usuario de <em>virt-manager</em>. Tenemos que ejecutar:</p>
<pre><code class="lang-sh">sudo virsh edit &lt;máquina_virtual&gt;
</code></pre>
<p>desde la línea de comandos y modificar el XML —que describe la máquina virtual—  a mano para añadir antes de la etiqueta <code>&lt;os&gt;</code> lo siguiente:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">cputune</span>&gt;</span>  
  <span class="hljs-tag">&lt;<span class="hljs-name">vcpupin</span> <span class="hljs-attr">vcpu</span>=<span class="hljs-string">'0'</span> <span class="hljs-attr">cpuset</span>=<span class="hljs-string">'0'</span>/&gt;</span>  
  <span class="hljs-tag">&lt;<span class="hljs-name">vcpupin</span> <span class="hljs-attr">vcpu</span>=<span class="hljs-string">'1'</span> <span class="hljs-attr">cpuset</span>=<span class="hljs-string">'1'</span>/&gt;</span>  
  <span class="hljs-tag">&lt;<span class="hljs-name">vcpupin</span> <span class="hljs-attr">vcpu</span>=<span class="hljs-string">'2'</span> <span class="hljs-attr">cpuset</span>=<span class="hljs-string">'2'</span>/&gt;</span>  
  <span class="hljs-tag">&lt;<span class="hljs-name">vcpupin</span> <span class="hljs-attr">vcpu</span>=<span class="hljs-string">'3'</span> <span class="hljs-attr">cpuset</span>=<span class="hljs-string">'3'</span>/&gt;</span>  
<span class="hljs-tag">&lt;/<span class="hljs-name">cputune</span>&gt;</span>
</code></pre>
<p><strong><em>ADVERTENCIA:</em></strong> <em>Ojo con olvidar el comando</em> <code>sudo</code>. <em>Si nos olvidamos de</em> <code>sudo</code> al ejecutar <code>virsh</code>, el comando puede fallar con el error <code>error: Domain not found</code> por no encontrar la máquina virtual o acabaremos editando una máquina virtual diferente a la que hemos configurado en virt-manager.</p>
<p>En mi sistema las CPU de la 0 a la 3 corresponde con los núcleos del primero al cuarto. Mientras que las CPU de la 4 a la 7 son hilos de esos mismos núcleos. Como hemos configurado la máquina virtual con 4 núcleos de 1 hilo, vinculamos cada uno de esos 4 núcleos virtuales con uno de los 4 núcleos de la CPU real.</p>
<p>La topología de las CPU reales de nuestro sistema se puede conocer mirando <code>/proc/cpuinfo</code> en el sistema anfitrión.</p>
<h1 id="heading-huge-pages">Huge Pages</h1>
<p>Además, se puede indicar que el proceso de la máquina virtual use páginas de memoria de gran tamaño o <a target="_blank" href="https://www.kernel.org/doc/Documentation/vm/hugetlbpage.txt"><em>huge pages</em></a>. El tamaño de página típico son 4 KB, pero algunas CPU permiten tamaños superiores —en la familia x86 se admiten páginas de 4 kB, 2 MB y 1 GB, según el modelo de CPU— lo que evita consultar algunos niveles de más en la tabla de página, durante la traducción de las direcciones virtuales y permite consumir menos entradas de la <a target="_blank" href="https://es.wikipedia.org/wiki/Translation_Lookaside_Buffer">TLB</a>.</p>
<p>Para activar su uso, primero hay que editar el XML de la máquina virtual:</p>
<pre><code class="lang-sh">sudo virsh edit &lt;máquina_virtual&gt;
</code></pre>
<p>y añadir lo siguiente antes de la etiqueta <code>&lt;os&gt;</code>:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">memoryBacking</span>&gt;</span>  
  <span class="hljs-tag">&lt;<span class="hljs-name">hugepages</span>/&gt;</span>  
<span class="hljs-tag">&lt;/<span class="hljs-name">memoryBacking</span>&gt;</span>
</code></pre>
<p>Las <em>huge pages</em> pueden no estar disponibles cuando se necesitan debido a la fragmentación de la memoria. Por eso, si se quieren emplear, hay que configurar el sistema para reservar la cantidad necesaria durante el arranque:</p>
<pre><code class="lang-sh"><span class="hljs-built_in">echo</span> <span class="hljs-string">"vm.nr_hugepages=2048"</span> | sudo tee /etc/sysctl.d/hugepages.conf
</code></pre>
<p>Donde 2048 páginas de 2 MB son 4096 MB, suficiente para una máquina virtual de 4 GB. Sin embargo, hay que tener presente que la memoria reservada no puede ser usada con otro propósito ni puede ser intercambiada. Como mi sistema solo tiene 16 GB, yo he optado por no activar el uso de <em>huge pages</em>. Obviamente, tendría sentido activarlo si dispusiera de mucha más memoria.</p>
<h1 id="heading-asignar-a-la-maquina-virtual-la-gpu">Asignar a la máquina virtual la GPU</h1>
<p>Llegados a este punto, antes de continuar, lo primero que deberíamos hacer es <a target="_blank" href="https://support.microsoft.com/es-es/help/4027538">crear un punto de restauración</a> en Windows. Así, si las cosas se ponen muy mal, no tendremos que volver a empezar desde cero.</p>
<p>Volvemos a la configuración de la máquina virtual, hacemos clic en <strong>+ Agregar hardware</strong> y seleccionamos <strong>Dispositivo PCI anfitrión</strong>. Hay que escoger la tarjeta gráfica que queremos asignar. En mi caso es el dispositivo que dice <strong>0000:01:00:0 NVIDIA Corporation GM206 [Geforce GTX 950]</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1637026439242/7gyYIvf997.png" alt="Añadir la tarjeta gráfica como dispositivo PCI del anfitrión" class="image--center mx-auto" /></p>
<p>Lo mismo se hace con el dispositivo justo debajo —el <code>0000:01:00:1</code>— que es la salida de audio digital de la tarjeta gráfica a través del conector HDMI. A fin de cuentas, ambos dispositivos están en la misma tarjeta y no es conveniente asignar uno a la máquina virtual y el otro no.</p>
<p>Yo también hice lo mismo con el dispositivo <strong>0000:05:00:0 ASMedia Technology Inc. ASM1042 SuperSpeed USB Host Controller</strong> para tener puertos USB donde conectar directamente un teclado, un ratón, un <em>gamepad</em> o un <em>pendrive</em>; si hiciera falta.</p>
<p>En principio para una tarjeta gráfica AMD esto sería todo. Al iniciar la máquina virtual ya no debería inicializarse en el monitor virtual en <em>virt-manager</em>. En su lugar debemos ver el arranque en el monitor físico conectado a la tarjeta gráfica. Una vez haya arrancado Windows, vamos a la web de fabricante de la GPU, bajamos los controladores para el dispositivo y los instalamos. Es preferible seleccionar el controlador adecuado nosotros mismos antes que utilizar la autodetección, ya que esto último puede dar problemas.</p>
<p>Sin embargo, <a target="_blank" href="https://ubuntuforums.org/showthread.php?t=2289210">con Windows 10 algunos usuarios informan de que pueden ser necesarios algunos trucos adicionales</a>. En mi caso intenté una actualización de Windows 8.1 a Windows 10 que no se completaba, si no editaba el XML de la máquina virtual</p>
<pre><code class="lang-sh">sudo virsh edit &lt;máquina_virtual&gt;
</code></pre>
<p>para eliminar toda la etiqueta <code>&lt;hyperv&gt;</code> en <code>&lt;features&gt;</code> y añadir lo siguiente:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">kvm</span>&gt;</span>  
  <span class="hljs-tag">&lt;<span class="hljs-name">hidden</span> <span class="hljs-attr">state</span>=<span class="hljs-string">'on'</span>/&gt;</span>  
<span class="hljs-tag">&lt;/<span class="hljs-name">kvm</span>&gt;</span>
</code></pre>
<p>De hecho mi etiqueta <code>&lt;features&gt;</code> es así:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">features</span>&gt;</span>  
  <span class="hljs-tag">&lt;<span class="hljs-name">acpi</span>/&gt;</span>  
  <span class="hljs-tag">&lt;<span class="hljs-name">apic</span>/&gt;</span>  
  <span class="hljs-tag">&lt;<span class="hljs-name">pae</span>/&gt;</span>  
  <span class="hljs-tag">&lt;<span class="hljs-name">kvm</span>&gt;</span>  
    <span class="hljs-tag">&lt;<span class="hljs-name">hidden</span> <span class="hljs-attr">state</span>=<span class="hljs-string">'on'</span>/&gt;</span>  
  <span class="hljs-tag">&lt;/<span class="hljs-name">kvm</span>&gt;</span>  
<span class="hljs-tag">&lt;/<span class="hljs-name">features</span>&gt;</span>
</code></pre>
<p>Cuando se tiene una GPU de NVIDIA hace falta cambiar lo mismo, independientemente de la versión de Windows, para que funcione. También se recomienda buscar la etiqueta <code>&lt;timer name=’hypervclock’ ... &gt;</code> dentro de <code>&lt;clock&gt;</code> y dejarla de esta manera...</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">timer</span> <span class="hljs-attr">name</span>=<span class="hljs-string">'hypervclock'</span> <span class="hljs-attr">present</span>=<span class="hljs-string">'no'</span>&gt;</span>
</code></pre>
<p>...o borrarla.</p>
<p>Con estos cambios el arranque debe ocurrir como hemos descrito anteriormente. Después solo tendremos que buscar el controlador adecuado e instalarlo.</p>
<h1 id="heading-activar-el-uso-de-message-signaled-interrupts-msi">Activar el uso de Message Signaled Interrupts (MSI)</h1>
<p><a target="_blank" href="https://en.wikipedia.org/wiki/Message_Signaled_Interrupts">MSI</a> es una alternativa al mecanismo tradicional de señalar las interrupciones mediante líneas dedicadas, que puede proporcionar una pequeña mejora de rendimiento.</p>
<p>Para activar su uso con nuestra tarjeta gráfica, básicamente tenemos que:</p>
<ol>
<li><p>Comprobar en el <strong>Administrador de dispositivos</strong> que la tarjeta soporta MSI. Lo más probable es que sí.</p>
</li>
<li><p>Ejecutar <code>regedit</code> en Windows, localizar la clave de registro del dispositivo y añadir allí la configuración que activa el uso de MSI para el dispositivo.</p>
</li>
</ol>
<p>Todos los detalles del proceso están perfectamente descritos en el primer mensaje de <a target="_blank" href="https://forums.guru3d.com/threads/windows-line-based-vs-message-signaled-based-interrupts.378044/">este hilo</a> en un foro.</p>
<h1 id="heading-detalles-finales">Detalles finales</h1>
<p>Si todo ha ido bien, ya tenemos una máquina virtual con una GPU real. Como ya no estamos usando el visor de <em>virt-manager</em>, quizás haga falta conectar temporalmente un teclado y un ratón a los puertos USB reales que le hemos asignado.</p>
<h2 id="heading-teclado-y-raton-compartido">Teclado y ratón compartido</h2>
<p>Eso de tener dos teclados no es muy práctico a largo plazo, por lo que utilizo <a target="_blank" href="https://symless.com/synergy"><em>Synergy</em></a> para compartir el teclado y el ratón del anfitrión con la máquina virtual. También permite compartir el portapapeles entre ambos sistemas.</p>
<p>En <code>conf/synergy.conf</code> dentro de mí <a target="_blank" href="https://github.com/jesustorresdev/virtual-desktop">repositorio</a> hay un ejemplo de mi configuración de <em>Synergy</em>. <em>Synergy</em> hace que al llegar al borde derecho de mi monitor en el sistema anfitrión, este aparezca por la izquierda en el monitor de la máquina virtual.</p>
<p>Este comportamiento a veces da problemas con juegos o con herramientas de edición 3D. Para esos casos he configurado la combinación de teclas <kbd>Alt+W</kbd> para que al pulsarla se confine el ratón al escritorio del sistema en el que esté en ese momento. Así el ratón y la entrada de teclado no puede cambiar de un sistema a otro por error.</p>
<p><em>Synergy</em> usa la red para conectar servidor y cliente, pero al usar <em>macvtap</em>, anfitrión y máquina virtual no pueden. Por eso he añadido a la máquina virtual una nueva red virtual privada que solo la conecta con el anfitrión. Es a través de esa red aislada por la que conecta el cliente con el servidor de <em>Synergy</em>.</p>
<h2 id="heading-monitor-compartido">Monitor compartido</h2>
<p>En mi caso no tengo un monitor para cada sistema. Tengo dos para ambos. La gráfica integrada se conecta a ellos mediante salidas DVI, mientras que la gráfica asignada a la máquina virtual utiliza las salidas HDMI. Cambiando la entrada que me interesa en cada monitor, puedo elegir si quiero ver el escritorio de la máquina virtual o del anfitrión.</p>
<p>Tengo en mente un proyecto para poder hacer eso empleando combinaciones de teclas, evitando usar los incómodos controles de los monitores. Sin embargo, ya veremos si algún día me pongo a ello 😉.</p>
<h2 id="heading-sonido">Sonido</h2>
<p>El sonido es seguramente el aspecto con el que menos satisfecho estoy. Después de probar muchas alternativas, creo que las mejores opciones son:</p>
<ul>
<li><p><strong>Conectar directamente una tarjeta de sonido o unos auriculares</strong> en un puerto USB asignado a la máquina virtual por <em>PCI Passthrough</em>. Sin duda es así como se consigue la mejor calidad de sonido. También sirve la salida de audio HDMI de la tarjeta gráfica asignada. Se puede escuchar por los altavoces del monitor —si los tiene— o conectar algunos por la salida de audio que los monitores suelen traer. Si no queremos tener dos parejas de altavoces, una para cada sistema, ni estar conectando y desconectado cables según nos interese, podemos comprar un mezclador barato para combinar ambas salidas de audio y tener solo unos altavoces conectados.</p>
</li>
<li><p><strong>Usar una tarjeta de sonido virtual de red</strong>, como la del proyecto <a target="_blank" href="https://github.com/duncanthrax/scream">duncanthrax/scream</a>. La idea de la tarjeta virtual de red es instalar en Windows un controlador de dispositivo de tarjeta de sonido que realmente envíe el audio por red a otro equipo para su reproducción. En ese sentido, el proyecto <em>scream</em> proporciona tanto los controladores para Windows como el servidor para Linux. El resultado es bastante bueno, prácticamente sin distorsiones ni latencia.</p>
</li>
<li><p><strong>Añadir un dispositivo de sonido emulado a la máquina virtual</strong> y que <em>QEMU</em> haga el resto. Esta es la solución típica. Necesita muchos ajustes y al final el resultado no es muy satisfactorio. Pero voy a explicar como lo he configurado yo.</p>
</li>
</ul>
<p>Primero hay que añadir un dispositivo de sonido a la máquina virtual. En mi caso, tras varias pruebas, he dejado el modelo ICH9, que es bastante moderno y funciona perfectamente.</p>
<p>Luego hay que indicar a <em>QEMU</em> como reproducir en el anfitrión el sonido del dispositivo emulado. Simplemente, editamos el XML de la máquina virtual:</p>
<pre><code class="lang-sh">sudo virsh edit &lt;máquina_virtual&gt;
</code></pre>
<p>y añadimos lo siguiente al final:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">qemu:commandline</span>&gt;</span>  
  <span class="hljs-tag">&lt;<span class="hljs-name">qemu:env</span> <span class="hljs-attr">name</span>=<span class="hljs-string">'QEMU_AUDIO_DRV'</span> <span class="hljs-attr">value</span>=<span class="hljs-string">'pa'</span>/&gt;</span>  
  <span class="hljs-tag">&lt;<span class="hljs-name">qemu:env</span> <span class="hljs-attr">name</span>=<span class="hljs-string">'QEMU_PA_SERVER'</span> <span class="hljs-attr">value</span>=<span class="hljs-string">'127.0.0.1'</span>/&gt;</span>  
  <span class="hljs-tag">&lt;<span class="hljs-name">qemu:env</span> <span class="hljs-attr">name</span>=<span class="hljs-string">'QEMU_PA_SAMPLES'</span> <span class="hljs-attr">value</span>=<span class="hljs-string">'1024'</span>/&gt;</span>  
<span class="hljs-tag">&lt;/<span class="hljs-name">qemu:commandline</span>&gt;</span>
</code></pre>
<p>Esto hace que <em>QEMU</em> use el servidor <em>pulseaudio</em> del anfitrión para reproducir el sonido, al igual que el resto de aplicaciones de Linux.</p>
<p>El valor de <code>QEMU_PA_SAMPLES</code> permite controlar el tamaño del buffer de muestras. Con valores muy altos, se consigue una calidad similar a la que se obtiene con <em>Scream</em>, al menos durante los primeros minutos. Sin embargo, el retardo es excesivo, haciendo imposible ver un vídeo. Con 1024 el retardo es inapreciable, pero la calidad del sonido no es tan alta.</p>
<p>Por defecto <em>pulseaudio</em> no acepta conexiones de red por TCP. Para resolverlo hay que editar <code>/etc/pulse/default.pa</code> y descomentar la línea del módulo <code>module-native-protocol-tcp</code> y que quede así:</p>
<pre><code class="lang-plaintext">load-module module-native-protocol-tcp auth-ip-acl=127.0.0.1
</code></pre>
<p>Por defecto, si tenemos activado el monitor virtual VNC, <em>Libvirt</em> ignorará lo indicado en <code>QEMU_AUDIO_DRV</code> para redirigir todo el sonido por VNC, tanto si el cliente VNC sabe reproducir el audio como si no es de esta manera. Es necesario editar <code>/etc/libvirt/qemu.conf</code> y asegurarnos que la siguiente línea está descomentada y aparece de esta forma:</p>
<pre><code class="lang-plaintext">vnc_allow_host_audio = 1
</code></pre>
<p>para que <em>Libvirt</em> haga siempre lo indicado por <code>QEMU_AUDIO_DRV</code>.</p>
<p>Por último, hay que indicar a Windows que la frecuencia de muestreo por defecto del dispositivo de audio es 44100 Hz, que es la frecuencia de muestreo por defecto en Linux. El valor por defecto en Windows es 48000 Hz. Si la frecuencia de muestreo en Windows y en Linux no coincide, oiremos los sonidos distorsionados. Los pasos son:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1637026439248/0wbRdmc_hg.png" alt="Configuración de la frecuencia de muestreo en Windows 10" class="image--center mx-auto" /></p>
<ol>
<li><p>En la máquina virtual hay que buscar el icono del altavoz en la bandeja del sistema, hacer clic con el botón derecho del ratón y seleccionar <strong>Abrir Configuración de sonido</strong>.</p>
</li>
<li><p>Hacer clic en <strong>Panel de control de sonido</strong>.</p>
</li>
<li><p>En <strong>Reproducción</strong> seleccionar <strong>Altavoces (High Definition Audio Device)</strong> y luego hacer clic en propiedades.</p>
</li>
<li><p>Hacer clic en la pestaña <strong>Opciones avanzadas</strong>.</p>
</li>
<li><p>Hacer clic en la lista de selección y escoger <strong>16 bits, 44100 Hz (Calidad de CD)</strong>.</p>
</li>
<li><p>Aplicar y salir.</p>
</li>
</ol>
<p>Y ya solo queda reproducir algo para ver como suena. En mi caso el sonido va acompañado a ratos de unos clics. Dependiendo de para qué vayamos a usar la máquina virtual, es posible que nos interese probar otra solución de las comentadas.</p>
<h2 id="heading-evitar-el-reinicio-de-xorg">Evitar el reinicio de Xorg</h2>
<p>En el <a target="_blank" href="https://jesustorres.es/escritorio-virtual-de-windows-10-parte-1#heading-liberar-la-grafica">artículo anterior</a> vimos que si cambiamos la tarjeta gráfica usada por nuestro escritorio en Linux mediante el comando <code>prime-select</code>, estamos obligados a salir de la sesión y reiniciar el gestor de pantalla; para posteriormente volver a iniciar sesión en el escritorio y lanzar la máquina virtual, de manera que esta pueda usar la tarjeta gráfica liberada.</p>
<p>Como esto puede resultar bastante tedioso si estamos cambiamos de tarjeta gráfica con frecuencia, podemos optar por ejecutar el escritorio en el sistema Linux siempre en la tarjeta gráfica integrada. De modo que la otra tarjeta gráfica estará disponible, por lo general, para ejecutar la máquina virtual.</p>
<p>En caso de querer aprovechar la tarjeta gráfica no discreta con algún programa del escritorio Linux —por ejemplo, un juego o alguna otra aplicación que se beneficie de utilizar un hardware gráfico más potente, cuando no la está utilizando la máquina virtual— podemos utilizar el comando <code>primusrun</code>:</p>
<pre><code class="lang-sh">primusrun &lt;comando&gt;
</code></pre>
<p>O, en caso de querer desactivar VSync, lo utilizaríamos así:</p>
<pre><code class="lang-sh">vblank_mode=0 primusrun &lt;comando&gt;
</code></pre>
<p>También se puede usar <a target="_blank" href="https://github.com/Witko/nvidia-xrun">nvidia-xrun</a>, un script que similar a <code>primusrun</code>, pero que es específico para tarjetas gráficas de NVIDIA y que suele ofrecer mejor rendimiento.</p>
<h2 id="heading-vfio-tools">VFIO-Tools</h2>
<p>Una alternativa muy interesante a mis scripts es <a target="_blank" href="https://github.com/PassthroughPOST/VFIO-Tools">VFIO-Tools</a>. Básicamente, se trata de una solución más modular, que facilita mucho crear scripts de hook personalizados que se ejecuten cuando la máquina virtual se inicia o detiene.</p>
<p>Algunos de los scripts que trae de serie hacen cosas como: configurar las <em>huge pages</em> —por lo que es importante desactivarlo si no nos interesa esta funcionalidad— ajustar la prioridad de los hilos que la máquina virtual usa para simular las CPU virtuales —lo que puede mejorar los tiempos de respuesta— y conmutar la entrada del monitor para que muestre la máquina virtual automáticamente cuando esta se inicia.</p>
]]></content:encoded></item><item><title><![CDATA[Escritorio virtual de Windows 10 (I)]]></title><description><![CDATA[Este artículo pertenece a una serie donde se explica como instalar Windows 10 en una máquina virtual asignándole una de las GPU del equipo de forma exclusiva, para obtener un rendimiento gráfico similar al que tendría en una máquina real. En esta par...]]></description><link>https://jesustorres.es/escritorio-virtual-de-windows-10-parte-1</link><guid isPermaLink="true">https://jesustorres.es/escritorio-virtual-de-windows-10-parte-1</guid><category><![CDATA[desktop]]></category><category><![CDATA[Linux]]></category><category><![CDATA[Windows]]></category><category><![CDATA[spanish]]></category><dc:creator><![CDATA[Jesús Torres]]></dc:creator><pubDate>Wed, 18 Sep 2019 21:36:51 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1637027622712/8pCPPB-W3.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>Este artículo pertenece a una serie donde se explica como instalar Windows 10 en una máquina virtual asignándole una de las GPU del equipo de forma exclusiva, para obtener un rendimiento gráfico similar al que tendría en una máquina real.</em> <em>En esta parte veremos como crear la máquina virtual e instalar Windows 10.</em> <em>Si te has perdido algún artículo anterior de esta historia, el primero lo tienes</em> <a target="_blank" href="/iommu-primer-asalto"><em>aquí</em></a> <em>y el segundo</em> <a target="_blank" href="/iommu-la-maldicion-de-la-vga"><em>aquí</em></a>.</p>
<hr />
<p>Como he comentado en artículos anteriores, quiero instalar Windows 10 en una máquina virtual sobre Ubuntu 18.04 LTS. Como estoy interesado en conseguir el máximo rendimiento gráfico en Windows, quiero que la máquina virtual tenga acceso exclusivo a la tarjeta gráfica, dejando para Ubuntu la gráfica integrada de Intel que viene con la placa madre.</p>
<p>Para que esta configuración funcione es necesario:</p>
<ol>
<li><p>Una CPU y una placa madre con soporte para la tecnología VT-d —o Intel® Virtualization Technology for Directed I/O, que es el nombre que Intel le da a la tecnología de la IOMMU—. En algunos casos hay que activar dicho soporte desde la BIOS / UEFI.</p>
</li>
<li><p>Una tarjeta gráfica con una ROM que soporte UEFI. La mía es una Geforce GTX 950, pero cualquier tarjeta gráfica de los últimos años sirve.</p>
</li>
</ol>
<h1 id="heading-instalacion-del-software">Instalación del software</h1>
<p>Para empezar necesitamos <em>QEMU/KVM</em>, <em>Libvirt</em>, <em>OVMF</em> y <em>Virtual Machine Manager</em>:</p>
<pre><code class="lang-sh">sudo apt-get install qemu-kvm ovmf libvirt-clients \
libvirt-daemon-system bridge-utils virt-manager
</code></pre>
<p><a target="_blank" href="https://virt-manager.org/"><em>Virtual Machine Manager</em></a> (o <em>virt-manager</em>) será la aplicación que utilizaremos para configurar y lanzar la máquina virtual. Básicamente, se trata de una aplicación de escritorio para gestionar máquinas virtuales a través de <a target="_blank" href="https://libvirt.org/"><em>Libvirt</em></a>, por lo que esta última se instará automáticamente como dependencia del primero.</p>
<p>Para que podamos lanzar máquinas virtuales con <em>virt-manager</em> necesitamos que nuestro usuario esté dentro del grupo <code>libvirt</code>. Podemos añadirlo así:</p>
<pre><code class="lang-sh">sudo adduser $(id -un) libvirt
</code></pre>
<p>Obviamente, tendremos que cerrar la sesión y volver a iniciarla para que el cambio tenga efecto.</p>
<p>Nuestra máquina virtual necesita un <a target="_blank" href="https://es.wikipedia.org/wiki/Extensible_Firmware_Interface">firmware UEFI</a> para arrancar —como el de cualquier placa madre real— por lo que emplearemos el del proyecto <a target="_blank" href="https://github.com/tianocore/tianocore.github.io/wiki/OVMF"><em>OVMF</em></a> (siglas de Open Virtual Machine Firmware) que es un firmware UEFI especialmente preparado para máquinas virtuales <em>QEMU/KVM</em>.</p>
<p>Desde <a target="_blank" href="https://www.kraxel.org/repos/jenkins/edk2/">el repositorio de Gerd Hoffmann</a> se puede obtener la última versión compilada de <em>OVMF</em>. De hecho eso fue lo que hice la primera vez, al configurar una máquina virtual de esta manera en una Ubuntu 16.04 LTS. Sin embargo, actualmente no debería haber ningún problema con la versión de <em>OVMF</em> empaquetada con cualquier distribución moderna, así que nos saltaremos ese paso.</p>
<h1 id="heading-activar-iommu">Activar IOMMU</h1>
<p>Lo primero es activar el soporte de <a target="_blank" href="/iommu-primer-asalto">IOMMU</a> en el núcleo. Para eso editamos <code>/etc/default/grub</code> y añadimos <code>intel_iommu=on</code> a la variable <code>GRUB_CMDLINE_LINUX_DEFAULT</code>. Después ejecutamos:</p>
<pre><code class="lang-sh">sudo update-grub
</code></pre>
<p>para actualizar la configuración del gestor de arranque con la nueva opción.</p>
<p>En algunos casos se ha informado de problemas durante el arranque o al reproducir sonido a través del HDMI de la gráfica integrada. Los efectos pueden ser diversos y diferentes entre sistemas. Por ejemplo, algunos informes hablan específicamente de problemas al usar el audio HDMI en procesadores de la micro-arquitectura Haswell, pero no siempre se pueden conectar estos problemas con un hardware concreto.</p>
<p>El asunto es que en caso de problemas es buena idea probar a desactivar la IOMMU para la gráfica integrada, utilizando la opción <code>intel_iommu=on,igfx_off</code>. De hecho mi configuración es:</p>
<pre><code class="lang-sh">GRUB_CMDLINE_LINUX_DEFAULT=<span class="hljs-string">"intel_iommu=on,igfx_off quiet splash"</span>
</code></pre>
<p>Además, se sabe que hay una importante pérdida de rendimiento en los procesadores Sandy Bridge al activar IOMMU. En ese caso se recomienda usar la opción <code>intel_iommu=pt</code> en lugar de <code>intel_iommu=on</code>. En la <a target="_blank" href="https://www.kernel.org/doc/Documentation/Intel-IOMMU.txt">documentación de Linux</a> hay más información sobre la configuración de IOMMU en Intel.</p>
<p>Una vez actualizada la configuración del gestor de arranque, debemos reiniciar el sistema y comprobar que el soporte de IOMMU está activado examinando los registros del sistema:</p>
<pre><code class="lang-sh">journalctl -b | grep DMAR
</code></pre>
<p>Vamos por el buen camino si en la salida del comando anterior vemos una línea que dice:</p>
<pre><code class="lang-plaintext">kernel: DMAR: IOMMU enabled
</code></pre>
<p>Si hemos usado la opción <code>igfx_off</code>, además debe haber otra con lo siguiente:</p>
<pre><code class="lang-plaintext">kernel: DMAR: Disable GFX device mapping
</code></pre>
<p>Si observamos que el soporte de IOMMU no se activa, puede ser que se nos hayamos olvidado activar el soporte de VT-d en la configuración de la BIOS/UEFI de nuestro sistema. O tal vez nuestra CPU o nuestra placa madre no tengan soporte para VT-d.</p>
<h1 id="heading-registro-de-dispositivos-en-vfio">Registro de dispositivos en VFIO</h1>
<p>Las aplicaciones de virtualización como <em>QEMU/KVM</em> necesitan acceso al dispositivo que se quiere mapear. Para hacerlo utilizan las facilidades de <a target="_blank" href="https://www.kernel.org/doc/Documentation/vfio.txt">VFIO</a>, que es un controlador de dispositivo de Linux cuya función es ofrecer a los procesos en modo usuario acceso directo a los dispositivos. Este tipo de acceso es lo que necesita la aplicación de virtualización, pero también puede ser útil para desarrollar controladores de dispositivo que se ejecuten en modo no privilegiado.</p>
<p>VFIO no puede ofrecer a las aplicaciones acceso a cualquier dispositivo del sistema. Solo lo hace a aquellos que han sido registrados previamente en VFIO. Y para que eso sea posible, el dispositivo no puede estar siendo usado por otro controlador.</p>
<p>Pongamos por caso que, como queremos hacer <em>VGA passthrough</em>, nos interesa registrar nuestra tarjeta gráfica en VFIO. Lo primero es obtener la lista de dispositivos, ejecutando el comando:</p>
<pre><code class="lang-sh">lspci -nn
</code></pre>
<p>El resultado será similar al de la siguiente imagen. La línea marcada corresponde con la tarjeta gráfica, instada en mi ordenador, que quiero utilizar con la máquina virtual:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1637025881816/xQ_STZhvXM.png" alt="Ejemplo al ejecutar el comando &quot;lspci -nn&quot;" class="image--center mx-auto" /></p>
<p>El texto <code>[10de:1002]</code> del final de la línea marcada nos indica que el fabricante de esa tarjeta gráfica tiene el identificador <code>0x10DE</code> y que el modelo se identifica como <code>0x1402</code>. Así que para registrar esta tarjeta habría que indicarle al controlador VFIO estos identificadores de la siguiente manera:</p>
<pre><code class="lang-sh"><span class="hljs-built_in">echo</span> 10DE 1402 |sudo tee /sys/bus/pci/drivers/vfio-pci/new_id
</code></pre>
<p>El problema es que esto hay que hacerlo antes de iniciar la máquina virtual y para cada dispositivo que queremos asignarle. En mi caso no solo es la tarjeta gráfica, también el dispositivo de audio HDMI de la misma tarjeta —justo en la línea siguiente— y un concentrador raíz USB —el ASM1042 SuperSpeed USB Host Controller— para poder conectar directamente un teclado y ratón USB, en caso de que hiciera falta.</p>
<p>Además, antes de registrar estos dispositivos en VFIO, hay que desregistrarlos del controlador de dispositivo que Linux le haya asignado para usarlos en el sistema anfitrión. En el caso particular de las tarjetas gráficas, es incluso mejor descargar el controlador de dispositivo correspondiente, porque no suelen llevar muy bien que les asignen y les quiten dispositivos en caliente durante la ejecución.</p>
<p>Para no hacerlo a mano en cada ocasión, es interesante tener un <em>hook</em> de <em>Libvirt</em> que lo haga automáticamente cada vez que se inicia la máquina virtual.</p>
<h1 id="heading-instalar-el-libvirt-hook">Instalar el libvirt hook</h1>
<p>En el repositorio <a target="_blank" href="https://github.com/jesustorresdev/virtual-desktop">jesustorresdev/virtual-desktop</a> he ido poniendo scripts y archivos de configuración relevantes para este proyecto. Dentro del directorio <code>libvirt-hooks</code> está el script <code>qemu</code>, que es el <em>hook</em> que se encargará del registro en VFIO durante el arranque de la máquina virtual.</p>
<p>Se puede instalar así:</p>
<pre><code class="lang-sh">sudo install -m755 libvirt-hooks/qemu /etc/libvirt/hooks
</code></pre>
<p><a target="_blank" href="https://libvirt.org/hooks.html#script-names">Libvirt admite 5 scripts de hook</a>. El script <code>qemu</code> se ejecuta cuando libvirt inicia, detiene o migra una máquina virtual de <em>QEMU</em>; que es exactamente nuestro caso. Eso significa que si tenemos varias máquinas virtuales de QEMU y queremos hacer cosas diferentes para cada una, debemos ponerlo todo en el mismo script <code>/etc/libvirt/hooks/qemu</code>.</p>
<p>Del script hay dos funciones a las que merece la pena echar un vistazo. Una es <code>vfio_bind_devices()</code> que, dado el identificador de un dispositivo, lo registra en VFIO para hacer <em>PCI passthrough</em>.</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">vfio_bind_devices</span>(<span class="hljs-params">device_ids</span>):</span>
    <span class="hljs-string">"""Bind the specified devices to the Linux VFIO driver
    :param device_ids: List of addresses of devices to bind to VFIO.
    :return: Dictionary with information about the device bound.
    """</span>

    vfio_loaded = <span class="hljs-literal">False</span>
    nvidia_loaded = <span class="hljs-literal">True</span>

    devices = {}
    <span class="hljs-keyword">for</span> id <span class="hljs-keyword">in</span> device_ids:
        device_path = <span class="hljs-string">'/sys/bus/pci/devices/%s'</span> % id
        <span class="hljs-keyword">try</span>:
            device_driver = os.path.basename(os.readlink(device_path + <span class="hljs-string">'/driver'</span>))
        <span class="hljs-keyword">except</span> OSError:
            device_driver = <span class="hljs-literal">None</span>

        <span class="hljs-comment"># Ignore devices already bound to VFIO driver because the system</span>
        <span class="hljs-comment"># crashes sometimes after a few bind/unbind cycles</span>
        <span class="hljs-keyword">if</span> device_driver != <span class="hljs-string">'vfio-pci'</span>:
            device_info = {
                <span class="hljs-string">'path'</span>: device_path,
                <span class="hljs-string">'driver'</span>: device_driver
            }
            <span class="hljs-keyword">with</span> open(device_path + <span class="hljs-string">'/vendor'</span>, <span class="hljs-string">'r'</span>) <span class="hljs-keyword">as</span> f:
                device_info[<span class="hljs-string">'vendor'</span>] = f.read()
            <span class="hljs-keyword">with</span> open(device_path + <span class="hljs-string">'/device'</span>, <span class="hljs-string">'r'</span>) <span class="hljs-keyword">as</span> f:
                device_info[<span class="hljs-string">'model'</span>] = f.read()
            devices[id] = device_info
        <span class="hljs-keyword">else</span>:
            vfio_loaded = <span class="hljs-literal">True</span>

    <span class="hljs-comment"># Load vfio-pci module, if needed</span>
    <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> vfio_loaded <span class="hljs-keyword">and</span> devices:
        subprocess.check_call([<span class="hljs-string">'modprobe'</span>, <span class="hljs-string">'vfio-pci'</span>])

    <span class="hljs-keyword">for</span> id, device_info <span class="hljs-keyword">in</span> devices.iteritems():
        <span class="hljs-comment"># Unbind the device if it is bound to other driver</span>
        <span class="hljs-keyword">if</span> device_info[<span class="hljs-string">'driver'</span>] <span class="hljs-keyword">is</span> <span class="hljs-keyword">not</span> <span class="hljs-literal">None</span>:

            <span class="hljs-comment"># Unload the NVIDIA driver instead of unbind the device</span>
            <span class="hljs-keyword">if</span> device_info[<span class="hljs-string">'driver'</span>] == <span class="hljs-string">'nvidia'</span>:

                <span class="hljs-comment"># Hotplug support of graphics card isn't good. Further, I </span>
                <span class="hljs-comment"># guess that question 9 applies here:</span>
                <span class="hljs-comment"># http://vfio.blogspot.com.es/2014/08/vfiovga-faq.html</span>
                <span class="hljs-comment"># The driver locks the VGA arbiter, freezing the VM on its </span>
                <span class="hljs-comment"># first access to VGA resources.</span>

                <span class="hljs-comment"># That shouldn't happen but...</span>
                <span class="hljs-comment"># https://bbs.archlinux.org/viewtopic.php?pid=1508940#p1508940</span>
                <span class="hljs-keyword">if</span> nvidia_loaded:
                    subprocess.call([<span class="hljs-string">'rmmod'</span>, <span class="hljs-string">'nvidia_drm'</span>])
                    subprocess.call([<span class="hljs-string">'rmmod'</span>, <span class="hljs-string">'nvidia_modeset'</span>])
                    subprocess.call([<span class="hljs-string">'rmmod'</span>, <span class="hljs-string">'nvidia_uvm'</span>])
                    subprocess.check_call([<span class="hljs-string">'rmmod'</span>, <span class="hljs-string">'nvidia'</span>])
                    nvidia_loaded = <span class="hljs-literal">False</span>
            <span class="hljs-keyword">else</span>:
                <span class="hljs-keyword">with</span> open(device_info[<span class="hljs-string">'path'</span>] + <span class="hljs-string">'/driver/unbind'</span>, <span class="hljs-string">'w'</span>) <span class="hljs-keyword">as</span> f:
                    f.write(id)

        <span class="hljs-comment"># Bind the device to VFIO driver</span>
        <span class="hljs-keyword">with</span> open(<span class="hljs-string">'/sys/bus/pci/drivers/vfio-pci/new_id'</span>, <span class="hljs-string">'w'</span>) <span class="hljs-keyword">as</span> f:
            f.write(<span class="hljs-string">"%s %s"</span> % (device_info[<span class="hljs-string">'vendor'</span>], device_info[<span class="hljs-string">'model'</span>]))

    <span class="hljs-keyword">return</span> devices
</code></pre>
<p>Da una idea de todos los pasos que habría que hacer si quisiéramos hacerlo a mano. Trata el caso de las tarjetas gráficas NVIDIA de forma especial, puesto que con esas GPU es recomendable descargar los módulos correspondientes del núcleo.</p>
<p>La otra función es el método <code>LibvirtHook.on_host_prepare()</code>, que contiene el código que llama a <code>vfio_bind_devices()</code> antes del inicio de la máquina virtual de nombre "hoth", que es el nombre mi máquina virtual con Windows.</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">on_hoth_prepare</span>(<span class="hljs-params">self</span>):</span>
    <span class="hljs-string">"""Hook method to 'prepare' the start of a VM named 'hoth'
    """</span>
    <span class="hljs-comment"># Bind the PCI devices to passthrough to VFIO driver</span>
    device_ids = [
        format_device_id(**address.attrib)
        <span class="hljs-keyword">for</span> address <span class="hljs-keyword">in</span> self.object_description.findall(<span class="hljs-string">"devices/hostdev[@type='pci']/source/address"</span>)
    ]
    vfio_bind_devices(device_ids)

    <span class="hljs-comment"># Start all the networks where the VM will be connected</span>
    network_names = [
        source.get(<span class="hljs-string">'network'</span>)
        <span class="hljs-keyword">for</span> source <span class="hljs-keyword">in</span> self.object_description.findall(<span class="hljs-string">"devices/interface[@type='network']/source"</span>)
    ]
    <span class="hljs-keyword">for</span> network_name <span class="hljs-keyword">in</span> network_names:
        network = self.virt_connection.networkLookupByName(network_name)
        <span class="hljs-keyword">if</span> network <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> network.isActive():
            network.create()
</code></pre>
<p>Si nuestra máquina virtual se llama "foo", solo necesitamos renombrar el método como <code>on_foo_prepare()</code>.</p>
<p>Este método no solo registra los dispositivos en VFIO para hacer <em>PCI passthrough</em>. También busca las redes virtuales a las que está conectada la máquina virtual y le indica a libvirt que las active.</p>
<h1 id="heading-liberar-la-grafica">Liberar la gráfica</h1>
<p>El script anterior únicamente podrá descargar el controlador de la tarjeta gráfica si no es la que estamos usando actualmente para el escritorio de Linux. Podemos consultar qué gráfica está utilizando actualmente nuestro entorno gráfico ejecutando:</p>
<pre><code class="lang-sh">$ prime-select query  
nvidia
</code></pre>
<p>Si estamos usando la tarjeta gráfica, podemos seleccionar la gráfica integrada ejecutando:</p>
<pre><code class="lang-sh">prime-select intel
</code></pre>
<p>Después tendremos que reiniciar el sistema o salir de la sesión de escritorio y reiniciar el gestor de pantalla:</p>
<pre><code class="lang-sh">sudo systemctl restart display-manager
</code></pre>
<h1 id="heading-crear-la-maquina-virtual">Crear la máquina virtual</h1>
<p>Hecho todo esto, podemos lanzar <em>virt-manager</em> para crear nuestra máquina virtual. Seleccionamos la opción de menú <strong>Archivo/Nueva máquina virtual</strong>, se nos abrirá el asistente y seguimos los pasos indicados:</p>
<ol>
<li><p>Instalación mediante <strong>Medio de instalación local</strong>.</p>
</li>
<li><p>Seleccionamos <strong>Utilizar imagen ISO</strong> y seleccionamos la imagen ISO con el contenido del CD de instalación de Windows.</p>
</li>
<li><p>Asignamos el número de CPU disponibles y la cantidad de memoria RAM. En mi caso la máquina virtual tiene 4 CPU y 8 GB de RAM. Sin embargo, posteriormente veremos cómo indicar que la cantidad real asignada sea menor.</p>
</li>
<li><p>Indicamos el tamaño del disco duro de la máquina virtual. Yo opté por usar un <a target="_blank" href="https://es.wikipedia.org/wiki/Logical_Volume_Manager">volumen lógico LVM</a>, dentro del mismo grupo de volumen que contiene los volúmenes lógicos de mi sistema anfitrión Linux. Aunque no voy a detenerme en explicar cómo se hace.</p>
</li>
<li><p>Por defecto la imagen del disco duro se guarda en un archivo con formato <a target="_blank" href="https://en.wikipedia.org/wiki/Qcow"><strong>qcow2</strong></a>. Eso es interesante si queremos ahorrar espacio, dado que empieza siendo un archivo muy pequeño y su tamaño aumenta dinámicamente según va ocupando espacio la máquina virtual. Pero si lo que nos interesa es el mejor rendimiento, mejor optar por el formato <strong>raw</strong>. En ese caso elegimos <strong>Seleccionar o crear almacenaje personalizado</strong> y le pedimos crear un nuevo volumen. Nos dejará escoger el nombre del archivo, formato y tamaño.</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1637025881798/g-_tXyrttk.png" alt="Crear un volumen del almacenamiento en formato &quot;raw&quot;" class="image--center mx-auto" /></p>
<p>En la última ventana marcamos <strong>Personalizar antes de instalar</strong> y finalmente le damos un nombre.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1637025881790/L29rJwKqgX.png" alt="Último paso en el asistente de creación de la máquina virtual" class="image--center mx-auto" /></p>
<p>Al pulsar en finalizar se abre la ventana de detalles de la nueva máquina virtual.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1637025881796/bKjX02RrOO.png" alt="Detalles generales de configuración antes de iniciar la instalación" class="image--center mx-auto" /></p>
<p>Seleccionamos el firmware UEFI, en lugar de BIOS, y el modelo del <em>chipset</em>. La configuración más segura es con <a target="_blank" href="https://es.wikipedia.org/wiki/Intel_440FX">i440FX</a>. A mí no me fue posible iniciar la instalación con Q35, puesto que con ese <em>chipset</em> la interfaz con los discos duros es AHCI y la versión de OVMF que estaba utilizando no lo soportaba. Entonces intenté añadir un chip PIIX4, para tener una interfaz IDE a la que conectar el disco duro, pero Windows no era capaz de verlo durante la instalación.</p>
<p>En principio, la primera opción debería ser i440FX, dejando Q35 para los casos en los que el primero no funciona. Por ejemplo, si queremos instalar una máquina virtual con macOS.</p>
<p>Aceptamos y avanzamos a la configuración de las CPU:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1637025881780/KWw4__4YCR.png" alt="Detalles sobre la configuración de las CPU antes de iniciar la instalación" class="image--center mx-auto" /></p>
<p>Aquí lo adecuado es indicar como modelo <strong>host-passthrough</strong>. Esta opción no está en la lista desplegable, así que tendremos que escribirla a mano. Básicamente, le dice a <em>KVM</em> que "pase" a la máquina virtual la CPU del anfitrión tal cual, sin modificaciones.</p>
<p>Además, se puede modificar la topología, es decir, cómo se exponen las CPU a la máquina virtual. Como se puede ver he optado porque la máquina virtual tenga una sola CPU, con 4 núcleos y un hilo de ejecución en cada uno.</p>
<p>Lo siguiente es modificar la configuración del disco duro principal: <strong>IDE Disco 1</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1637025881782/Y8vH_WqLP8.png" alt="Detalles sobre la configuración del disco duro antes de iniciar la instalación" class="image--center mx-auto" /></p>
<p>Por defecto <em>QEMU</em> emula una interfaz IDE para el acceso al disco duro. Sin embargo, se puede mejorar el rendimiento desplegando <strong>Opciones avanzadas</strong> y cambiando <strong>Bus de disco</strong> a SCSI. Luego se pulsa en <strong>Agregar hardware</strong> y se añade un <strong>Controlador</strong> del tipo <strong>SCSI</strong> y modelo <strong>VirtIO SCSI</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1637025881792/griz0jJQE7.png" alt="Añadir un controlador de disco VirtIO SCSI" class="image--center mx-auto" /></p>
<p><a target="_blank" href="https://es.wikibooks.org/wiki/QEMU/Dispositivos/Virtio">VirtIO</a> es una interfaz de disco paravirtualizada. Es decir, no emula una interfaz de disco real, como IDE o SCSI; sino que la máquina virtual sabe que es una interfaz por software diseñada para virtualización. El resultado es un mayor rendimiento. Sin embargo, Windows no sabe acceder a estos dispositivos si no se le proporcionan controladores adecuados durante la instalación.</p>
<p>Para que estos controladores estén disponibles necesitamos una segunda unidad de CDROM. Pulsamos en <strong>Agregar hardware</strong> y añadimos <strong>Almacenamiento</strong> de tipo de dispositivo CDROM y tipo de bus IDE.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1637025881788/r_MS7uapzW.png" alt="Añadir una unidad de CDROM para los controladores VirtIO" class="image--center mx-auto" /></p>
<p>Hay que indicar que use la imagen ISO con los controladores VirtIO. La última versión se puede descargar desde <a target="_blank" href="https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/latest-virtio/">aquí</a>.</p>
<p>Finalmente, pulsamos en iniciar la instalación.</p>
<p>Si el firmware UEFI no inicia la instalación, sino que nos deja en una interfaz de línea de comandos como la siguiente:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1637025881773/L-Rg8RKi0.png" alt="Interfaz de línea de comandos de OVMF" class="image--center mx-auto" /></p>
<p>tendremos que buscar y lanzar nosotros mismos el arranque del instalador, ubicado seguramente en <code>FS0:\EFI\BOOT\BOOTX64</code>:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1637025881784/YY7f6W87cY.png" alt="Pasos para localizar el arranque del instalado de la ISO de Windows" class="image--center mx-auto" /></p>
<p>Llegados a este punto la instalación debería proceder con normalidad. Cuando nos pregunte dónde instalar Windows, pulsamos en la opción de <strong>Cargar controlador</strong>, buscamos la unidad de CDROM con los controladores VirtIO y navegamos por las carpetas hasta <code>viosci\w10\amd64</code>, para instalar los controladores de 64 bits para Windows 10.</p>
<p>Una vez instalado el controlador, el instalador nos dejará seleccionar el disco duro virtual como unidad de destino y completar la instalación.</p>
<hr />
<p><em>En la</em> <a target="_blank" href="/escritorio-virtual-de-windows-10-parte-2"><em>siguiente parte</em></a> <em>veremos algunos ajustes interesantes para optimizar la máquina virtual y detalles adicionales para trabajar con el escritorio virtual de forma más cómoda.</em></p>
]]></content:encoded></item><item><title><![CDATA[SnapRAID y MergerFS para almacenar archivos de forma fiable (y II)]]></title><description><![CDATA[Encabeza este artículo "HDD" por amendch.
Este artículo corresponde a una serie donde se explica como usar SnapRAID y MergerFS para disponer de un almacenamiento fiable formado por varios discos duros en un ordenador de sobremesa. Si te has perdido l...]]></description><link>https://jesustorres.es/snapraid-y-mergerfs-para-almacenar-archivos-de-forma-fiable-parte-2</link><guid isPermaLink="true">https://jesustorres.es/snapraid-y-mergerfs-para-almacenar-archivos-de-forma-fiable-parte-2</guid><category><![CDATA[Backup]]></category><category><![CDATA[Linux]]></category><category><![CDATA[sysadmin]]></category><category><![CDATA[spanish]]></category><dc:creator><![CDATA[Jesús Torres]]></dc:creator><pubDate>Wed, 27 Feb 2019 11:29:01 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1635808319255/C6FxZZjZC.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>Encabeza este artículo "HDD" por</em> <a target="_blank" href="https://www.flickr.com/photos/39244466@N02/5427739593/in/photolist-9gCzT8-4UVUNJ-71Mb5R-91d5pX-oMFTx2-oMFQjD-5gDHxc-4oTnmH-bqrKL-6437bG-d3uXp7-9LgqFA-8bJz7i-3imxtM-ERbLe-7nGAFG-5gDHup-4oTnXc-9LgmKu-75fHu-qkKNAp-oWpoqT-pLwxeF-3KCpZN-9LgmbA-emkmar-9wLNNj-yoKes9-9Lgo3b-6j1N5L-xxhYh-ERcmU-9Lgrcw-dmA143-2DJQw-foCdqf-5wWien-9wHQvp-c9yGns-5TQgX3-2zEFt-VXYVdD-5SCmBK-6ViFwn-uHRq7-5TQoVw-s2QEx-uHRAy-VGJxwS-DCBbHY"><em>amendch</em></a>.</p>
<p><em>Este artículo corresponde a una serie donde se explica como usar SnapRAID y MergerFS para disponer de un almacenamiento fiable formado por varios discos duros en un ordenador de sobremesa.</em> <em>Si te has perdido la parte anterior, la tienes</em> <a target="_blank" href="/snapraid-y-mergerfs-para-almacenar-archivos-de-forma-fiable-parte-1"><em>aquí</em></a><em>.</em></p>
<hr />
<h1 id="heading-automatizar-la-ejecucion-de-snapraid">Automatizar la ejecución de SnapRAID</h1>
<p>Obviamente, no podemos depender de acordarnos de ejecutar <em>SnapRAID</em> cada día. Así que lo que corresponde es automatizar su ejecución para que tenga lugar periódicamente.</p>
<p>Por fortuna <a target="_blank" href="https://zackreed.me">Zack Reed</a> ofrece un script perfecto para la tarea, que yo mismo he modificado para adaptarlo a mis necesidades. El script original está disponible <a target="_blank" href="https://zackreed.me/updated-snapraid-sync-script/">aquí</a>. Mientras que el mío lo está en <a target="_blank" href="https://gist.github.com/jesustorresdev/1ca6f96580be6e21957f877cfa3d5125">GitHub Gist</a>.</p>
<p>Para instalarlo simplemente hay que descargarlo y copiarlo en <code>/usr/local/sbin/snapraid_diff_n_sync.sh</code>. Después solo es necesario crear el archivo <code>/etc/cron.d/snapraid</code> con el siguiente contenido:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># /etc/cron.d/snapraid: crontab entries for snapraid package</span>
<span class="hljs-comment"># Run a SnapRAID diff and then sync  </span>
30 23   * * *   root  /usr/<span class="hljs-built_in">local</span>/sbin/snapraid_diff_n_sync.sh
</code></pre>
<p>De esta forma el script será ejecutado automáticamente como <code>root</code> todos los días a las 23:30.</p>
<p>La diferencia entre el script original y el mío, es que el primero utiliza el correo electrónico para notificar cualquier problema detectado durante la ejecución. Sin embargo, yo lo uso en un sistema de escritorio, por lo que prefiero que los mensajes se muestren en el área de notificaciones de la barra de tareas.</p>
<p>Para eso el script invoca otro script llamado <code>notify-send-all</code>, que sirve para enviar un mensaje a todos los usuarios con una sesión de escritorio activa. Este script también debe ser descargado y copiado en la ruta <code>/usr/local/sbin/notify-send-all</code>.</p>
<div class="gist-block embed-wrapper" data-gist-show-loading="false" data-id="e8810dbceece820b4ae5aa0ee5ca200a"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a href="https://gist.github.com/jesustorresdev/e8810dbceece820b4ae5aa0ee5ca200a" class="embed-card">https://gist.github.com/jesustorresdev/e8810dbceece820b4ae5aa0ee5ca200a</a></div><p> </p>
<p>Finalmente, puede ser necesario editar <code>snapraid_diff_n_sync.sh</code> para ajustar su configuración. Esta configuración está disponible bajo la línea:</p>
<pre><code class="lang-bash"><span class="hljs-comment">## USER DEFINED SETTINGS ##</span>
</code></pre>
<ul>
<li><p><code>DEL_THRESHOLD</code>, indica un umbral de archivos borrados. Por ejemplo, si se establece a 50, la sincronización no tendrá lugar si se detecta que más del 50% de los archivos han sido borrados.</p>
</li>
<li><p><code>SCRUB_PERCENT</code>, indica el porcentaje de los datos que serán validados una vez se haya completado la sincronización. Es decir, en cada ejecución se comprueba la integridad de una parte de los datos almacenados.</p>
</li>
<li><p><code>SCRUB_AGE</code>, indica la antigüedad mínima en días que debe tener un bloque para ser seleccionada para verificar su integridad.</p>
</li>
</ul>
<p>Una vez hecho, periódicamente la información de paridad se sincronizará con los últimos cambios y parte de nuestros datos más antiguos serán comprobados.</p>
<h1 id="heading-mergerfs">MergerFS</h1>
<p>Ahora tenemos varios discos protegidos gracias a la información de paridad almacenada en el disco correspondiente. Sin embargo, todos nuestros datos están repartidos entre discos diferentes. Sería mucho mejor si pudiéramos acceder a todos los discos como si fueran un único dispositivo de almacenamiento. Para eso es para lo que usaremos <em>MergerFS</em>.</p>
<p>Los paquetes de <em>MergerFS</em> para distintas distribuciones se pueden descargar desde <a target="_blank" href="https://github.com/trapexit/mergerfs/releases">GitHub</a>. Después solo hay que instalar <em>FUSE</em> y el paquete descargado. Por ejemplo:</p>
<pre><code class="lang-bash">sudo apt-get install fuse  
sudo dpkg -i mergerfs_2.25.1.ubuntu-xenial_amd64.deb
</code></pre>
<p>Luego se crea el punto de montaje:</p>
<pre><code class="lang-bash">sudo mkdir -p /media/storage/pool
</code></pre>
<p>Y se edita <code>/etc/fstab</code> para añadir la siguiente línea asegurar que se montan automáticamente durante el arranque del sistema:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># BIBLIOTECA: MergerFS  </span>
/media/storage/data* /media/storage/pool fuse.mergerfs defaults,allow_other,moveonenospc=<span class="hljs-literal">true</span>,minfreespace=20G,fsname=storage 0 0
</code></pre>
<p>Esta línea monta todos discos de datos accesibles en <code>/media/storage</code> y los presenta como un único dispositivo de almacenamiento en <code>/media/storage/pool</code>.</p>
<h2 id="heading-opciones">Opciones</h2>
<p>Es interesante echar un vistazo a <a target="_blank" href="https://github.com/trapexit/mergerfs#options">todas las opciones que soporta MergerFS</a> durante el montaje. Como son muchas, únicamente voy a comentar las que utilizo yo:</p>
<ul>
<li><p><code>allow_other</code>, permite que el sistema de archivos sea accesible por usuarios diferentes al que lo montó. Como se monta automáticamente desde <code>/etc/fstab</code>, ese usuario es el <code>root</code>, por lo que esta opción es necesaria para poder usarlo desde una cuenta de usuario corriente del sistema.</p>
</li>
<li><p><code>moveonenospc=true</code>, si la escritura de datos en uno de los discos falla por falta de espacio, MergerFS buscará el disco con más espacio libre y con hueco suficiente para el archivo, moverá el archivo que se intenta modificar ahí y volverá a intentar la escritura.</p>
</li>
<li><p><code>minfreespace=20G</code>, asegura que a la hora de crear archivos nuevos solo se utilizarán aquellos discos con más de 20GB de espacio libre.</p>
</li>
<li><p><code>fsname</code>, la etiqueta del sistema de archivos con la que se mostrará en exploradores de archivos como Dolphin.</p>
</li>
</ul>
<h2 id="heading-politicas">Políticas</h2>
<p>Tenemos que tener presente que <em>MergerFS</em> soporta diferentes políticas a la hora de crear y modificar los archivos. Por defecto:</p>
<ul>
<li><p>Al crear un archivo en una ruta concreta, de todos los discos donde exista esa misma ruta cogerá aquel con más espacio libre. Esta política sirve para controlar a dónde deben ir ciertos archivos, simplemente creando un directorio en el disco concreto que nos interese.</p>
</li>
<li><p>Al modificar las propiedades —o metadatos—  de un archivo en una ruta concreta, se modificarán todos los archivos que tengan la misma ruta en todos los discos.</p>
</li>
<li><p>Para abrir un archivo se buscará en los discos según el orden indicado y se abrirá el primero que encuentre.</p>
</li>
</ul>
<p>Según el uso que le queramos dar al almacenamiento puede ser interesante cambiar alguna de las políticas por defecto. En <a target="_blank" href="https://github.com/trapexit/mergerfs#functions-categories-and-policies">la documentación de MergerFS están explicadas las diferentes opciones</a>.</p>
<h1 id="heading-mi-experiencia">Mi experiencia</h1>
<p>Llevo utilizando esta solución desde mayo de 2017 sin problemas. Empleo el almacenamiento para guardar la colección de fotografías de las vacaciones —gestionada con <em>digiKam</em>— copias de seguridad de documentos, manuales, programas originales y otros contenidos. Gracias a <em>Plex Server</em>, sirvo desde ahí los contenidos a otros dispositivos de la casa, sin ningún problema de rendimiento.</p>
<p>La sincronización ocurre todas las noches en segundo plano sin ningún inconveniente. A veces se queja con una notificación en el escritorio si ese mismo día he movido de sitio una carpeta con muchos archivos. Para resolverlo solo tengo que lanzar la sincronización manualmente, desde la línea de comandos. Pero eso es buena señal. Me da la seguridad de que si comento el error de hacer grandes cambios sin darme cuenta, la sincronización no tendrá lugar y podré volver hacia atrás fácilmente.</p>
<p>La política de asignación de espacio de <em>MergerFS</em> funciona bastante bien. El reparto del espacio ocupado en los discos es bastante equitativo.</p>
<p>Lo único que me falta es que un día falle un disco, para así comprobar si puedo sustituirlo por uno nuevo y recuperar su contenido con éxito. Crucemos los dedos 😉</p>
]]></content:encoded></item><item><title><![CDATA[SnapRAID y MergerFS para almacenar archivos de forma fiable (I)]]></title><description><![CDATA[Hace años que vengo pensando en adquirir una NAS para almacenar copias de seguridad de las cosas más importantes —las fotos de fiestas y viajes, algunos libros electrónicos, la tesis doctoral que nadie más leerá jamás y otros documentos—. Quizás incl...]]></description><link>https://jesustorres.es/snapraid-y-mergerfs-para-almacenar-archivos-de-forma-fiable-parte-1</link><guid isPermaLink="true">https://jesustorres.es/snapraid-y-mergerfs-para-almacenar-archivos-de-forma-fiable-parte-1</guid><category><![CDATA[Backup]]></category><category><![CDATA[Linux]]></category><category><![CDATA[sysadmin]]></category><category><![CDATA[spanish]]></category><dc:creator><![CDATA[Jesús Torres]]></dc:creator><pubDate>Mon, 18 Feb 2019 18:20:11 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1635808325954/n-brltjwW.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hace años que vengo pensando en adquirir una NAS para almacenar copias de seguridad de las cosas más importantes —las fotos de fiestas y viajes, algunos libros electrónicos, la tesis doctoral que nadie más leerá jamás y otros documentos—. Quizás incluso usarlo como <em>media server</em> para distribuir algunos de esos contenidos en la red de mi casa.</p>
<p>El asunto es que me gustaría preservar la información pero al mismo tiempo que sea accesible. Si por ejemplo me dedico a hacer copias de seguridad en DVD o a copiarla en discos externos, seguramente cogerán polvo en el estante de los cacharros electrónicos, por los siglos de los siglos. Y eso si me acuerdo de hacer la copia. Lo más probable es que no sea así y acabe perdiendo los datos igual.</p>
<p>Las NAS para almacenar varios TB siguen siendo un poco caras para mi presupuesto y, además, yo tengo un ordenador de sobremesa que me gustaría aprovechar. Una de esas torres con hueco suficiente para 8 discos duros, donde almacenar de sobra toda la información importante. Además, no tengo ninguna necesidad de tenerlo dando servicio constantemente. No me importa encenderlo solo cuando lo necesite.</p>
<p>Así que la cuestión es cómo almacenar gran cantidad de datos en varios discos duros de una manera que se accesible, fiable y sencilla. La primera respuesta que se nos puede ocurrir es usar algún tipo de RAID. Pero si los datos no tienen mucho movimiento, no hace falta protegerlos en tiempo real. De hecho, hacer una copia de seguridad periódica cada cierto tiempo sería suficiente. Solo que no quiero almacenar los datos por duplicado porque me parece tirar espacio de almacenamiento.</p>
<p>Es entonces cuando SnapRAID y MergerFS llegaron en mi ayuda.</p>
<h1 id="heading-raid">RAID</h1>
<p>En Linux tenemos muchas maneras de configurar un almacenamiento fiable para cubrir nuestras necesidades personales. Obviamente, si queremos lo mejor, podemos adquirir una controladora <a target="_blank" href="https://es.wikipedia.org/wiki/RAID">RAID</a> por hardware —incluso con batería propia, para mantener la información de la memoria caché de la controladora en caso de un fallo de alimentación—. Esta solución es muy eficiente y es transparente respecto al sistema operativo, porque la controladora se hace cargo de todos los detalles, pero suele ser excesiva para uso doméstico.</p>
<p><a target="_blank" href="https://commons.wikimedia.org/wiki/File:Adaptec_2020SA_SATA_RAID_controller.jpg"><img src="https://cdn-images-1.medium.com/max/2560/1*hwwilWxI575J82CtiwsXOQ.jpeg" alt="Controladora RAID SATA Adaptec 2020SA" class="image--center mx-auto" /></a></p>
<p>Por mucho menos están las controladoras FakeRAID. De hecho es muy probable que la placa madre de nuestro ordenador ya venga con alguna funcionalidad de este tipo. En ese caso solo se implementa en el hardware y en el firmware de la controladora lo necesario para configurar los discos y para dar soporte al uso de volúmenes en RAID durante el arranque. Posteriormente el sistema operativo se hace cargo de la gestión de los volúmenes RAID usando su propia implementación basada en software. Las controladoras FakeRAID, a diferencia de las soluciones en Linux basadas al 100% en software, dan soporte a todo el arranque del sistema y permiten disponer de distintos sistemas operativos en el mismo almacenamiento RAID. Por lo demás, tienen las mismas prestaciones que cualquier otra solución basada al 100% en software.</p>
<p>Linux dispone de una amplia variedad de soluciones con RAID basado en software. Las más clásicas son las independientes del sistema de archivos, como <a target="_blank" href="https://es.wikipedia.org/wiki/Logical_Volume_Manager">LVM</a> o <a target="_blank" href="https://en.wikipedia.org/wiki/Mdadm">MD</a>. Ambas permiten configurar varios dispositivos —o incluso particiones individuales, en el caso de LVM— como un único volumen que podemos formatear con el sistema de archivos que más nos guste. Sin embargo, Linux también soporta algunos sistemas de archivos que integran la funcionalidad del RAID por software, como ZFS o Btrfs, lo que siempre es más cómodo de gestionar que cuando tenemos que lidiar con dos componentes independientes.</p>
<h2 id="heading-inconvenientes">Inconvenientes</h2>
<p>La verdad es que optar por ZFS o Btrfs y hacer instantáneas —o <em>snapshots</em>— de los datos sería de lo más sencillo. El problema es que parece que ZFS necesita bastante memoria para funcionar adecuadamente —desde que ZFS apareció para Solaris han surgido diversas versiones para Linux, con limitaciones y requisitos diferentes que han variado con el tiempo, así que esto puede que ya no sea cierto, pero no me he parado a comprobarlo—. Mientras que Btrfs sigue sin ofrecer el rendimiento y la fiabilidad de EXT4.</p>
<p>Además, muchas de las soluciones comentadas evitan la perdida de datos, en caso del fallo de unos de los discos, manteniendo una segunda copia de estos. Es lo que se llama RAID-1. Pero como he dicho, no estoy interesado en desperdiciar almacenamiento manteniendo dos copias de los datos. Prefiero otras soluciones más eficientes en almacenamiento, como RAID-5, que solamente guardan información de paridad con la que recuperar los datos en caso de que sea necesario. Es decir, esto se traduce en que si tengo 4 discos de 3TB:</p>
<ul>
<li><p>Con RAID-1, tendría 6TB de almacenamiento real y 6TB de datos redundantes.</p>
</li>
<li><p>Con RAID-5, tendría 9TB de almacenamiento real y 3TB de datos redundantes.</p>
</li>
</ul>
<p>RAID-5 puede consumir algo más de CPU y por eso las soluciones basadas en controladoras por hardware son las más atractivas cuando se necesita rendimiento, ya que la propia controladora se puede hacer cargo de ese trabajo extra, descargando a la CPU. Estas controladoras suelen tener su propia batería para mantener la memoria interna, lo que evita un problema llamado <em>agujero de escritura</em> —o <em>write hole</em>—. Un problema que, si no es tratado adecuadamente, puede llevar a la corrupción de los datos cuando ocurren fallos de alimentación —por eso la necesidad de la batería en la controladora—.</p>
<p>Pero las controladoras RAID por hardware son bastante caras. Mientras que la soluciones por software no siempre soportan RAID-5 o no tienen un soporte lo bastante maduro. Por ejemplo, el soporte de RAID-5 en MD existe desde 2001 pero hasta 2017 —Linux 4.11— no se ha introducido <a target="_blank" href="https://lwn.net/Articles/665299/">un mecanismo para cerrar el <em>write hole</em></a> con ayuda de un disco adicional SSD que se usa como registro de transacciones. En LVM el soporte de RAID-5 es de 2013 pero, aparte de imponer varias limitaciones a la hora de gestionar los volúmenes, aún no se ha incluido una solución similar a la de MD para cerrar el <em>write hole</em>. Y como LVM comparte código con el soporte de las controladoras FakeRAID, es posible que estas últimas tenga el mismo problema. Por su parte, Btrfs aún no soporta RAID 5 de forma fiable y tampoco resuelve el problema del <em>write hole</em>. Mientras que ZFS ofrece una solución alternativas similar llamada RAID-Z. El problema, como hemos comentado, es que ZFS puede consumir una cantidad importante de memoria para funcionar adecuadamente.</p>
<h1 id="heading-snapraid">SnapRAID</h1>
<p><a target="_blank" href="https://www.snapraid.it/"><em>SnapRAID</em></a> es una alternativa a las soluciones anteriores, siempre que no necesitamos fiabilidad en tiempo real. Por ejemplo, es una buena opción si es razonable generar la información de recuperación periódicamente, sabiendo que los cambios entre esos intervalos de tiempo podrían perderse si fallara uno de los discos. Esto tiene todo el sentido cuando los archivos no se modifican con frecuencia.</p>
<p>Además, <em>SnapRAID</em> funciona sobre cualquier sistema de archivos y gestor de volúmenes, sin necesidad de formatear ni hacer cambios de formato. Simplemente le indicamos las particiones que queremos proteger y él se encarga. Estas particiones ya pueden contener datos y pueden tener tamaños diferentes.</p>
<p>En gran medida se parece a una solución tradicional de copias de seguridad, solo que no necesitamos duplicar el espacio disponible para hacer la copia. <em>SnapRAID</em> solo necesita un disco adicional para datos de paridad, como ocurre con RAID-5.</p>
<p>En cada ejecución, aparte de actualizar la información de recuperación, <em>SnapRAID</em> refresca algunos bloques de datos para evitar la degradación de los datos con el paso del tiempo. Muchos sistemas de archivos ignoran este fenómeno porque los datos se suelen manipular con cierta frecuencia. Pero si vamos a tener un almacenamiento de larga duración, no está de más comprobar los datos y refrescarlos periódicamente para evitar pérdidas.</p>
<h2 id="heading-configuracion-de-mi-sistema">Configuración de mi sistema</h2>
<p>En mi caso tengo 4 discos duros vacíos de 3TB, aproximadamente. De esos discos, 3 son para el almacenamiento de datos —<code>/dev/sdc</code>, <code>/dev/sdd</code> y <code>/dev/sde</code>—  y el que queda para el archivo de paridad —<code>/dev/sdb</code>—.</p>
<p>Hay que tener en cuenta que el archivo de paridad puede crecer tanto como el mayor de los discos de datos. Por lo tanto, no buena idea utilizar un disco de paridad pequeño.</p>
<h2 id="heading-preparacion-del-almacenamiento">Preparación del almacenamiento</h2>
<p>Para empezar desde cero creé una tabla de particiones GPT en cada disco, con una única partición EXT4 que ocupa todo el espacio, tanto para los discos de datos:</p>
<pre><code class="lang-sh">sudo mkfs.ext4 -m2 -Eresize=3T -LSTOR-DATA1 /dev/sdc1  
sudo mkfs.ext4 -m2 -Eresize=3T -LSTOR-DATA2 /dev/sdd1  
sudo mkfs.ext4 -m2 -Eresize=3T -LSTOR-DATA3 /dev/sde1
</code></pre>
<p>como para el de paridad:</p>
<pre><code class="lang-sh">sudo mkfs.ext4 -m0 -Eresize=3T -Tlargefile4 -LSTOR-PAR1 /dev/sdb1
</code></pre>
<p>Respecto a las opciones de <code>mkfs.ext4</code> utilizadas:</p>
<ul>
<li><p><code>-m2</code>. Por lo general el 5% del espacio en disco se reserva para el superusuario. Esto permite evitar la fragmentación y garantiza que los procesos del root sigan funcionado, aunque un proceso no privilegiado haya llenado todo el disco. El asunto es que un 5% en 3TB son 150GB de almacenamiento reservado que nunca podrán utilizarse para datos. Esta opción permite rebajar el espacio reservado hasta el 2%, es decir, a 60GB.</p>
</li>
<li><p><code>-m0</code>. En el disco de paridad la fragmentación de archivos no es un problema porque solo va a estar ocupado por un único archivo de paridad. Por otro lado, no está de más que el archivo de paridad tenga un poco más de espacio para crecer que el total del disco de datos más grande. Como todos los discos son de igual tamaño, para tener algo más de espacio en el disco de paridad, se puede indicar durante el formateo esta opción y así no se reserva nada al superusuario. Adicionalmente, se puede indicar también la opción <code>-Tlargefile4</code>.</p>
</li>
<li><p><code>-Tlargefile4</code>. Esta opción optimiza el espacio usado por el propio sistema de archivos bajo la premisa de que en general se van a almacenar archivos de gran tamaño. Este es el caso del disco de paridad, por lo que es una buena idea usarlo al formatear, ganando así algo más de espacio libre. Sin embargo, antes de utilizarlo con los discos de datos es importante estar seguro del tamaño de los archivos que vamos a almacenar. En mi caso comprobé que el tamaño medio de los archivos que quería almacenar era de 2MB, así que no utilicé esta opción al formatear esos discos.</p>
</li>
<li><p><code>-Eresize=3T</code>. EXT4 por defecto permite extender el sistema de archivos hasta 1000 veces el tamaño original sin tener que desmontar la unidad. Para eso, durante el formateo, reserva espacio suficiente para sus estructuras internas. El problema es que ya estamos usando todo el espacio disponible en el disco para el sistema de archivos. Es imposible extender el sistema de archivos sin cambiar de dispositivo. Así que se puede ganar algo de espacio libre indicando que el sistema de archivos nunca crecerá por encima de los 3TB.</p>
</li>
<li><p><code>-LSTOR-DATA1</code>. Una etiqueta para nombrar cada partición de una forma fácil de recordar.</p>
</li>
</ul>
<p>Una vez formateados, ya solo queda crear los puntos de montaje para los discos:</p>
<pre><code class="lang-sh">sudo mkdir -p /media/storage/{data1,data2,data3,parity1}
</code></pre>
<p>y editar <code>/etc/fstab</code> para asegurarnos que se montan automáticamente durante el arranque del sistema. Con añadir las siguientes líneas es suficiente:</p>
<pre><code class="lang-sh"><span class="hljs-comment"># BIBLIOTECA: disco de paridad de SnapRAID  </span>
LABEL=STOR-PAR1 /media/storage/parity1  ext4 defaults 0 2  
<span class="hljs-comment"># BIBLIOTECA: discos de datos  </span>
LABEL=STOR-DATA1 /media/storage/data1   ext4 defaults 0 2  
LABEL=STOR-DATA2 /media/storage/data2   ext4 defaults 0 2  
LABEL=STOR-DATA3 /media/storage/data3   ext4 defaults 0 2
</code></pre>
<p>En lugar de reiniciar podemos ejecutar <code>mount -a</code> para comprobar que el montaje de los discos funciona correctamente.</p>
<pre><code class="lang-sh">sudo mount -a
</code></pre>
<h2 id="heading-instalacion-y-configuracion-de-snapraid">Instalación y configuración de SnapRAID</h2>
<p>Para instalar SnapRAID en Ubuntu lo más sencillo es añadir el <a target="_blank" href="https://launchpad.net/~tikhonov/+archive/ubuntu/snapraid">PPA de Maxim Tikhonov</a>:</p>
<pre><code class="lang-sh">sudo add-apt-repository ppa:tikhonov/snapraid  
sudo apt-get update
</code></pre>
<p>y así poder instalarlo a través del gestor de paquetes de la distribución:</p>
<pre><code class="lang-sh">sudo apt-get install snapraid
</code></pre>
<p>para luego editar el archivo de configuración <code>/etc/snapraid.conf</code>:</p>
<pre><code class="lang-sh">sudo nano /etc/snapraid.conf
</code></pre>
<p>En dicho archivo, primero se indica la ruta al archivo de paridad en el directorio donde está montando el disco de paridad:</p>
<pre><code class="lang-sh"><span class="hljs-comment"># Defines the file to use as parity storage  </span>
<span class="hljs-comment"># It must NOT be in a data disk  </span>
<span class="hljs-comment"># Format: "parity FILE_PATH"  </span>
parity /media/storage/parity1/snapraid.parity
</code></pre>
<p>Después las rutas a los archivos de contenidos. Estos archivos almacenan las rutas de todos los archivos de datos protegidos por <em>SnapRAID</em>.</p>
<p>Al menos debe haber un archivo de contenido por archivo de paridad más uno adicional. Y cada archivo debe estar en un disco duro diferente. En mi caso guardo el archivo de contenidos en el sistema de archivos raíz en <code>/var/lib/snapraid/snapraid.content</code> y dos copias adicionales  —aunque solo estoy obligado a tener una más— en los discos de datos <code>STORAGE-DATA2</code> y <code>STORAGE-DATA3</code>.</p>
<pre><code class="lang-sh"><span class="hljs-comment"># Defines the files to use as content list  </span>
<span class="hljs-comment"># You can use multiple specification to store more copies  </span>
<span class="hljs-comment"># You must have least one copy for each parity file plus one.</span>

<span class="hljs-comment"># Some more don’t hurt  </span>
<span class="hljs-comment"># They can be in the disks used for data, parity or boot,  </span>
<span class="hljs-comment"># but each file must be in a different disk  </span>
<span class="hljs-comment"># Format: "content FILE_PATH"  </span>
content /var/lib/snapraid/snapraid.content  
content /media/storage/data2/snapraid.content  
content /media/storage/data3/snapraid.content
</code></pre>
<p>Ojo porque, si se configura igual, el directorio <code>/var/lib/snapraid/</code> debe existir antes de usar <em>SnapRAID</em> por primera vez.</p>
<p>Luego se indican las rutas a los puntos de montaje de los discos de datos:</p>
<pre><code class="lang-sh"><span class="hljs-comment"># Defines the data disks to use  </span>
<span class="hljs-comment"># The name and mount point association is relevant for parity, do  </span>
<span class="hljs-comment"># not change it  </span>
<span class="hljs-comment"># WARNING: Adding here your /home, /var or /tmp disks is NOT a good   </span>
<span class="hljs-comment"># idea!  </span>
<span class="hljs-comment"># SnapRAID is better suited for files that rarely changes!  </span>
<span class="hljs-comment"># Format: "disk DISK_NAME DISK_MOUNT_POINT"  </span>
data d1 /media/storage/data1  
data d2 /media/storage/data2  
data d3 /media/storage/data3
</code></pre>
<p>Y finamente las rutas dentro de los puntos de montaje de los discos de datos de archivos que serán excluidos de la sincronización:</p>
<pre><code class="lang-sh"><span class="hljs-comment"># Defines files and directories to exclude  </span>
<span class="hljs-comment"># Remember that all the paths are relative at the mount points  </span>
<span class="hljs-comment"># Format: "exclude FILE"  </span>
<span class="hljs-comment"># Format: "exclude DIR/"  </span>
<span class="hljs-comment"># Format: "exclude /PATH/FILE"  </span>
<span class="hljs-comment"># Format: "exclude /PATH/DIR/"  </span>
exclude *.unrecoverable  
exclude /tmp/  
exclude /lost+found/  
exclude .Trash-*/  
exclude .Thumbs.db  
exclude /Descargas/
</code></pre>
<p>Como se puede ver, he decidido ignorar los archivos de miniaturas y el directorio donde se guarda el contenido de la papelera del escritorio. Tampoco interesan archivos temporales ni aquellos recuperados durante reparaciones del sistema de archivos —que se almacenan en <code>/lost+found/</code>—. Además tengo una carpeta para descargas cuyo contenido tampoco quiero proteger. Si finalmente decido preservar alguno de esos archivos, ya lo moveré a otra carpeta no excluida.</p>
<p>Una vez hecho todo esto podemos sincronizar el array de discos, protegiendo su contenido:</p>
<pre><code class="lang-sh">sudo snapraid sync
</code></pre>
<h2 id="heading-usar-snapraid">Usar SnapRAID</h2>
<p><code>SnapRAID</code> soporta una lista bastante completa de subcomandos con los que gestionar nuestro array de discos. Entre muchos otros:</p>
<ul>
<li><p><code>snapraid sync</code>, actualiza la información de paridad leyendo todos los archivos modificados en los discos de datos y guardando la información de paridad corresponde.</p>
</li>
<li><p><code>snapraid scrub</code>, permite hacer comprobaciones periódicas de los datos y de la información de paridad. Usando las opciones <code>-p</code> y <code>-o</code> se pueden indicar los criterios para seleccionar los bloques de datos que serán verificados. Por ejemplo, con el comando<code>snapraid -p 5 -o 20 scrub</code> se indica que se quiere comprobar el 5% de los datos del array, siempre que se hayan verificado por última vez hace más de 20 días.</p>
</li>
<li><p><code>snapraid status</code>, muestra información sobre el estado del array de discos.</p>
</li>
<li><p><code>snapraid fix</code>, repara archivos perdidos o dañados. Básicamente verifica los datos con la información de paridad y si se encuentra alguna diferencia devuelve los archivos al estado en el que estaban cuando se hizo la sincronización. Usando <code>snapraid -f file fix</code> o <code>snapraid -f dir fix</code> se puede recuperar un archivo <code>file</code> o un directorio <code>dir</code> en particular.</p>
</li>
<li><p><code>snapraid smart</code>, muestra el informe <a target="_blank" href="https://es.wikipedia.org/wiki/S.M.A.R.T.">SMART</a> de todos los discos en el array.</p>
</li>
<li><p><code>snapraid check</code>, verificar todos los archivos y la información de paridad. Básicamente se utiliza si queremos hacer una verificación manual de los datos, por ejemplo, después de haber recuperado algún archivo.</p>
</li>
</ul>
<p>Sin embargo, no es muy realista pensar que cada día nos acordaremos de sincronizar los discos con los últimos cambios. Es mucho mejor automatizar la ejecución del SnapRAID, como veremos en el siguiente artículo.</p>
<p>Si al final te animas a probar <a target="_blank" href="https://www.snapraid.it/"><em>SnapRAID</em></a> y te resulta útil, no olvides que el proyecto <a target="_blank" href="https://www.snapraid.it/">admite donaciones</a> para ayudar a mantener su desarrollo.</p>
<p><em>(Parte 2,</em> <a target="_blank" href="/snapraid-y-mergerfs-para-almacenar-archivos-de-forma-fiable-parte-2"><em>aquí</em></a><em>)</em></p>
]]></content:encoded></item><item><title><![CDATA[IOMMU: La maldición de la VGA]]></title><description><![CDATA[Voy a explicar el problema con las gráficas integradas Intel (IGD) y las gráficas discretas antiguas que no soportan UEFI cuando se intenta crear un escritorio virtual Este artículo corresponde a una serie donde se explica como montar un sistema de e...]]></description><link>https://jesustorres.es/iommu-la-maldicion-de-la-vga</link><guid isPermaLink="true">https://jesustorres.es/iommu-la-maldicion-de-la-vga</guid><category><![CDATA[desktop]]></category><category><![CDATA[Linux]]></category><category><![CDATA[Windows]]></category><dc:creator><![CDATA[Jesús Torres]]></dc:creator><pubDate>Mon, 28 Jan 2019 07:01:01 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/unsplash/XIx85KpKmWU/upload/v1638554312805/eCyfY24lC.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>Voy a explicar el problema con las gráficas integradas Intel (IGD) y las gráficas discretas antiguas que no soportan UEFI cuando se intenta crear un escritorio virtual</em> <em>Este artículo corresponde a una serie donde se explica como montar un sistema de escritorio virtualizado, asignándole una GPU de forma exclusiva para obtener un rendimiento similar al de un sistema no virtualizado.</em> <em>Si te has perdido la parte anterior, la tienes</em> <a target="_blank" href="/iommu-primer-asalto"><em>aquí</em></a><em>.</em></p>
<hr />
<h1 id="heading-el-estandar-vga">El estándar VGA</h1>
<p>VGA es un estándar gráfico diseñado en 1987 y que aun hoy se sigue utilizando en PC. El estándar contempla muchos aspectos, pero para nosotros lo más relevante es cómo prevé que el resto del sistema tenga acceso a la tarjeta gráfica.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1637025361906/T7wn-Pr4Ig.jpg" alt="Conector VGA" /></p>
<p><em>Conector VGA —</em> <a target="_blank" href="https://commons.wikimedia.org/wiki/File:Male_VGA_connector.jpg"><em>Wikipedia</em></a></p>
<p>Toda tarjeta gráfica VGA tiene cierta cantidad de memoria de vídeo (VRAM). Esta memoria se asigna a la memoria del ordenador en una ventana de direcciones que va desde <code>0xA0000</code> a <code>0xBFFFF</code>. Es decir, que cuando la CPU accede a esas posiciones de la memoria del sistema realmente está accediendo a la memoria de vídeo de la tarjeta gráfica y no a la memoria RAM. Lamentablemente, con ese rango solo se pueden direccionar 128KB, que además se reparten entre regiones para modos gráficos, modos texto y compatibilidad con estándares anteriores. Por lo tanto, ese rango de direcciones era suficiente para los 640x480 y 16 colores originales del estándar VGA, pero es insuficiente para direccionar la memoria de las tarjetas gráficas modernas, que suelen venir con varios GB.</p>
<p>Las tarjetas gráficas también traen una memoria ROM con la Video BIOS (VBIOS) que no es sino un programa que debe ejecutarse durante el arranque del ordenador para iniciar la tarjeta correctamente. Este código es propio de cada fabricante para cada tarjeta. Por lo general se le asigna el rango de direcciones de <code>0xC0000</code> a <code>0xC7FFF</code> de la memoria del sistema. El objeto de esto es que durante el arranque la BIOS del sistema ejecute el código de la VBIOS —accesible en el rango de direcciones indicado— para iniciar la tarjeta gráfica VGA y que así se pueda utilizar desde las primeras fases del arranque para mostrar información por la pantalla.</p>
<h1 id="heading-tarjetas-graficas-modernas">Tarjetas gráficas modernas</h1>
<p>Las tarjetas gráficas modernas en buses PCI y PCIe son mucho más potentes que las antiguas tarjetas gráficas del estándar VGA, pero mantienen la compatibilidad hacia atrás.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1637928284940/PAvlpFMMK.png" alt="Mapa de memoria del sistema" class="image--center mx-auto" /></p>
<p>Durante el arranque, a las tarjetas gráficas modernas se les asigna un rango de direcciones más grande para poder acceder a su memoria de vídeo. Sin embargo, también se les asigna el rango de <code>0xA0000</code> a <code>0xC0000</code> y la VBIOS también se mapea en la memoria —ver el mapa de memoria anterior—. De esta forma, la BIOS del sistema se puede hacer cargo de iniciar la tarjeta gráfica durante las primeras fases del arranque. Y la tarjeta puede usarse por la BIOS, el gestor de arranque y hasta por el propio sistema operativo como una VGA convencional, hasta que este último carga los controladores de dispositivo correspondientes. A partir de ese instante, la interfaz VGA prácticamente deja utilizarse, ya que los controladores tienen acceso a todo el rango de direcciones asignado a la tarjeta y con eso a la interfaz específica que el fabricante haya preparado para acceder al dispositivo.</p>
<h1 id="heading-cuando-hay-mas-de-una-tarjeta-grafica">Cuando hay más de una tarjeta gráfica</h1>
<p>En un sistema moderno, una vez todo el sistema operativo ha terminado de arrancar, no es problema utilizar varias tarjetas gráficas a la vez. A fin de cuentas, cada una es un dispositivo diferente con su propio rango de direcciones y sus propios controladores.</p>
<p>El conflicto surge en las primeras fases del arranque, cuando ambas se comportan como tarjetas VGA que escuchan en el mismo rango de direcciones de la memoria principal. Por suerte, en los sistemas con buses PCI y PCIe se puede controlar qué tarjeta en cada momento es accesible a través de la interfaz VGA.</p>
<p>Durante el arranque, la BIOS selecciona una de las tarjetas gráficas como principal y le asigna a la interfaz VGA. Esa tarjeta es iniciada y el proceso se desarrolla como hemos comentado anteriormente. Una vez el sistema operativo ha cargado su controlador de dispositivo y ya no necesita más la vieja interfaz VGA, estas direcciones son asignadas a la tarjeta no principal, para iniciarla mediante su VBIOS, y luego cargar sus controladores de dispositivo, momento a partir del cual tampoco necesitará la interfaz VGA nunca más.</p>
<p>Hay que señalar que las tarjetas gráficas más actuales, aparte de soportar esta forma compatible con las BIOS de mapear su VBIOS e iniciarse, también soportan un modo más flexible, compatible con UEFI, que no necesita que se le asigne al código de la VBIOS de la tarjeta un rango fijo de direcciones de la memoria principal por debajo del primer MB. De esta manera se simplifican mucho las cosas cuando se quieren utilizar simultáneamente varias tarjetas gráficas, porque ya no es necesario utilizar con ellas la vieja interfaz del estándar VGA, ni siquiera durante el arranque para iniciarlas.</p>
<p>El proceso descrito es muy similar si la segunda gráfica no es usada en el mismo sistema anfitrión, sino que es asignada directamente a una máquina virtual para que la use directamente. Este es el caso que nos interesa para virtualizar el escritorio.</p>
<p>Incluso es posible arrancar múltiples máquinas virtuales al mismo tiempo, cada una con su propia tarjeta gráfica. Porque aunque todas necesiten usar el mismo rango de direcciones de la interfaz VGA, el sistema se encarga de evitar conflictos a través de lo que se llama el arbitraje VGA. Este componente del sistema anfitrión asigna el rango de direcciones VGA a una tarjeta o a la otra según se detecten intentos de acceso desde las máquinas virtuales, garantizando el acceso exclusivo de cada máquina virtual a su tarjeta a través del rango compartido de direcciones de la interfaz VGA, mientras sea necesario.</p>
<p>Vistas todas estas particularidades, parece vidente que, tal y como comentamos en <a target="_blank" href="iommu-primer-asalto">la primera parte</a>, el <em>PCI passthrough</em> de tarjetas gráficas es bastante más complejo que el de otro tipo de dispositivos. Aun así, con el soporte adecuado por parte de la CPU y del software de virtualización, no deberíamos tener problema para tener varias tarjetas gráficas discretas y asignarlas a nuestras máquinas virtuales.</p>
<h1 id="heading-graficas-integradas-intel">Gráficas integradas Intel</h1>
<p>El problema viene si queremos aprovechar la gráfica integrada Intel (IGD) que probablemente venga con nuestra placa madre. Seguramente no nos sirva para tener un escritorio para jugar a juegos recientes, pero si para otras actividades.</p>
<p>El arbitraje VGA tiene varias opciones para evitar que una tarjeta reclame una transacción en el rango de direcciones de la interfaz VGA:</p>
<ul>
<li><p>Desactivar el uso de este rango a través de algún mecanismo interno de la propia tarjeta.</p>
</li>
<li><p>Desactivar el acceso del dispositivo al bus PCI o PCIe.</p>
</li>
</ul>
<p>Lamentablemente, la capacidad de desactivar el rango de la interfaz VGA no funciona o ha sido eliminado de las IGD. El único mecanismo posible para evitar conflictos, es desactivar el acceso del dispositivo al bus. Sin embargo, eso también desactiva el acceso a través del resto del rango de direcciones asignado al dispositivo y los controladores no pueden hacer su trabajo si el acceso al dispositivo se mantiene desactivado permanente.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1637025361864/xXA43WuFG0.jpg" alt class="image--center mx-auto" /></p>
<p>Por lo tanto, las IGD no pueden asignarse a ninguna máquina virtual. Solo se pueden aprovechar como gráfica del sistema operativo anfitrión. Y, además, como acaparan el rango de direcciones VGA, es importante que las gráficas discretas asignadas a las máquinas virtuales no utilicen en ningún momento dicho rango. Por eso, en este caso particular, es necesario que las máquinas virtuales arranquen con UEFI —en lugar de con BIOS— y que las tarjetas gráficas tenga soporte UEFI, permitiendo así que la inicialización de la tarjeta se realice sin recurrir al estándar VGA.</p>
<p>Con esto aclarado, en futuras partes veremos como configurar un sistema de escritorio virtual con una GPU discreta, usando la IGD para el sistema anfitrión y empleado con <em>QEMU/KVM</em> y <em>libvirt</em>.</p>
<p><em>(Parte 3,</em> <a target="_blank" href="/escritorio-virtual-de-windows-10-parte-1"><em>aquí</em></a><em>)</em></p>
]]></content:encoded></item><item><title><![CDATA[Post mortem del Máster de Videojuegos de la ULL (Parte 3)]]></title><description><![CDATA[Lo prometido es deuda.
Esta vez he tardado un poco más de lo habitual porque se ha desencadenado una cascada de acontecimientos.
Esta semana el Consejo Social de la ULL ha parado el título propio y después la universidad ha dado vía libre al título o...]]></description><link>https://jesustorres.es/post-mortem-del-master-de-videojuegos-de-la-ull-parte-3</link><guid isPermaLink="true">https://jesustorres.es/post-mortem-del-master-de-videojuegos-de-la-ull-parte-3</guid><category><![CDATA[spanish]]></category><category><![CDATA[Complaints]]></category><category><![CDATA[university]]></category><dc:creator><![CDATA[Jesús Torres]]></dc:creator><pubDate>Thu, 08 Jun 2017 11:20:04 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1635808292225/112E10KBE.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>Lo prometido es deuda.</em>
<em>Esta vez he tardado un poco más de lo habitual porque se ha desencadenado una cascada de acontecimientos.</em>
<em>Esta semana <strong>el Consejo Social de la ULL ha parado el título propio y después la universidad ha dado vía libre al título oficial</strong> que proponía mi departamento.</em>
<em>Así que, por fortuna, nos toca seguir trabajando.</em></p>
<p><em>Si te has perdido alguna parte anterior de esta historia, la primera la tienes <a target="_blank" href="/post-mortem-del-master-de-videojuegos-de-la-ull-parte-1">aquí</a> y la segunda <a target="_blank" href="post-mortem-del-master-de-videojuegos-de-la-ull-parte-2">aquí</a></em>.</p>
<hr />
<p>Voy a dedicar esta última entrega a explicar cómo preparamos nuestra propuesta para su aprobación en el Consejo de Departamento del 17 de febrero, donde todo comenzó a torcerse.
Así que si estás esperando otra turbia historia sobre la universidad, mejor no sigas leyendo porque esta vez habrá mucho trabajo en equipo y compañerismo.</p>
<p>No tengo duda de que pusimos los medios para que todos los miembros de nuestro y otros departamentos pudieran participar en el desarrollo de este proyecto.
Entonces ¿por qué voy a contar algo que debería ser de lo más común en la universidad? En parte, porque desafortunadamente esta no suele la práctica más común.
Y fundamentalmente porque quiero desmontar los rumores que se han estado dispersando desde los despachos de los <em>mandamases universitarios</em>.
Esos que intentan justificar todas las maquinaciones que he relatado con la excusa de ser la única respuesta posible ante un supuesto problema de inquina personal.</p>
<p>Decía un compañero, que cuando la evidencia los deja sin argumentos, algunos no saben otra cosa más que refugiarse en el "es un problema personal".
Y eso cuando no usan el más feo y machista "es un problema de mujeres" —excusa que llevo escuchando desde que trabajo aquí, incluso en este caso, hasta por parte de otras mujeres—  como si con eso los problemas ya no fueran de verdad.
Es triste lo fácil que les resulta vender ese argumento en una universidad que se dice preocupada por la igualdad.</p>
<p>Señoras y señores, ya se que estoy gastando saliva inútilmente.
Se que van a seguir con su cantinela una y otra vez.
Pero aquí y ahora quiero dejar algunas cosas claras a todos los que lean esto:</p>
<ul>
<li><strong>Fuimos exquisitos facilitando que todos en el departamento pudieran participar</strong>.
En igualdad de condiciones, sin oportunidad de secuestrar o desviar el proyecto.
Usamos herramientas colaborativas y las discusiones fueron completamente abiertas.
<strong>Participó quién tuvo interés y se auto-excluyó quién así lo quiso</strong>.
Eso fue decisión de cada uno.</li>
<li>No existía antes y no creo que exista después ningún tipo de problema personal.
<strong>El único problema lo crearon los órganos de dirección de la universidad</strong>  —desde la dirección del departamento a la dirección de la universidad—  al ignorar repetidamente la decisión de un conjunto de profesores y dejarnos indefensos.</li>
<li>Esta guerra no escode ningún fin, ni personal ni político.
<strong>La he hecho mía porque soy uno de los profesores perjudicados, creo que es injusto lo que se nos ha hecho y detesto la falta de honestidad</strong>.
Fui leal al aceptar este trabajo para este equipo y al intentar resolver el conflicto por todos los medios posibles, antes de verme obligado a llegar a esto.</li>
</ul>
<p>Sinceramente, si alguien aun cree que quien ha escrito estas líneas no es sino un peón en una partida más importante, lo más que puedo hacer es invitarlo a unas cañas.
Amigo, lo tuyo no tiene más arreglo que el que charlemos y me conozcas un poco mejor.</p>
<h1 id="heading-cuando-todo-era-amor-y-buen-rollo">Cuando todo era amor y buen rollo</h1>
<p>Obviamente no me estoy inventando nada cuando digo que fuimos exquisitos y que no excluimos a nadie.</p>
<p>A principios de este curso comenzamos a debatir sobre el futuro del Máster Universitario en Ingeniería Informática porque somos el departamento con más carga docente en el mismo.
Si no recuerdo mal, al finalizar el curso anterior apenas teníamos dos nuevas matrículas.
Y creo que hubo que cazar alumnos casi a lazo para llegar a la cifra definitiva de 7.
Los números exactos son lo de menos.
Lo importante es que hemos ido bajando en número de matrículas de nuevo ingreso año tras año.</p>
<p>Por varios motivos, en noviembre de 2016 se abre al resto del departamento el debate de qué hacer con el actual Máster de Ingeniería Informática.
Una mayoría importante se manifiesta en el sentido que deberíamos abandonar el modelo de máster con formación generalista para pasar a ofertar formación especializada, orientada a cubrir perfiles concretos.
Entonces, entre correos electrónicos y reuniones, se pone sobre la mesa un Máster en Desarrollo Full-Stack y yo aprovecho la ventana de oportunidad para sacar la propuesta de Máster en Desarrollo de Videojuegos, en la que había estado trabajando desde principios de cursos.
Semanas después otro grupo de compañeros en el departamento propuso un Máster en Ciberseguridad e Inteligencia de Datos.
Compartimos documentos en Google Drive y nos pusimos a trabajar.
Todos pudimos aportar a cualquiera de los másteres y todos pudimos indicar nuestro interés en cualquiera de las asignaturas.</p>
<p>Como novedad, el 1 de febrero las propuestas oficiales elaboradas en el departamento se presentaron a 20 expertos de empresas y administraciones públicas en las llamadas Jornadas de Economía Digital en la ULL.
En el caso del Máster de Videojuegos, la propuesta fue felicitada.
Recogimos las ideas de los asistentes para incorporarlas en la ultima revisión, antes del primer intento de aprobarlo en Consejo de Departamento.</p>
<h1 id="heading-a-vueltas-con-las-comisiones">A vueltas con las comisiones</h1>
<p>Creo que lo que realmente molestó a algunas personas fue la novedad del "todos pudimos aportar", pues lo que hicimos ni mucho menos se ajustaba a los usos y costumbres en la universidad.</p>
<p>En un departamento como el mío, con aproximadamente 60 personas, lo común hubiera sido crear una comisión que se dedicara a la elaboración de los másteres.
Es la forma en la que solemos proceder para ser operativos y asegurarnos de que el trabajo se hace y los conflictos se resuelven antes de su aprobación por todo el Consejo de Departamento.
Pero en mi opinión eso a veces presenta algunos problemas.</p>
<p>El primero es que <strong>hace más difícil que todos se sienta implicados</strong>.
Resulta que estábamos pensando en crear titulaciones nuevas que iban a necesitar de mucho trabajo y dedicación.
Eso significa que necesitábamos docentes motivados para implicarse en la docencia, pero en la motivación uno de los factores que más influye es sentir que formas parte de algo.
Cuando optamos por hacer comisiones, compañeros que podrían tener mucho que aportar son dejados al margen del proyecto.
Se hace más complicado saber lo que se está haciendo o qué se está discutiendo.
Y, en caso de que se sepa, sólo se puede aportar a través de intermediarios.</p>
<p>El segundo problema <strong>es que es realmente difícil decidir qué personas deben estar en la comisión</strong> para que el proyecto siga siendo fiel a los principios originales.
Siendo sinceros con nosotros mismos, todos sabemos que hay personas que intentarán colar la asignatura que ellos quieren dar o reciclar ideas del pasado, aunque con eso desvirtúen el proyecto.
Pero obviamente no les puedes decir que se van a quedar fuera porque tu crees que harán eso.</p>
<p>Las comisiones son una herramienta golosa porque controlando su composición se controla lo que deciden.
Cuando después de muchos meses se presenta un proyecto consensuado por las partes para su aprobación, es complicado que alguien haga reparos a cosas que hubiera discutido si hubiera participado en el debate.
Ya está todo hecho y tiene el respaldo de la comisión, es hora de aprobarlo.
En gran medida <strong>las comisiones pueden usarse y se usan como una forma de hurtar la capacidad de decisión del colectivo</strong>.</p>
<p>Algunas personas reclaman que las comisiones deben de ser de expertos pero ¿qué expertos y quién lo decide?.
Nosotros tenemos profesores que llevan toda su vida investigado y dando docencia en videojuegos; investigadores que se dedican a la tecnología educativa, a la gamificación, a los dispositivos o al diseño de interacción; docentes que no saben específicamente del tema pero que tienen claro lo que quieren nuestros alumnos, que están alineados con los objetivos del proyecto o que están a la última en tecnología e innovación; personas que saben motivar a otras personas o incluso que pueden aportar cosas que ni se me ocurren, porque no conozco a cada uno de mis 59 compañeros.
Entonces, ¿cómo los seleccionamos y, sobre todo, cómo lo hacemos para que todo el mundo se sienta incluido?</p>
<p>Para mi la solución a este problema era muy sencilla.
Soy un friki del software libre, de las comunidades abiertas y de la colaboración.
Uso los Wiki como herramienta colaborativa antes de que por aquí se oyera hablar de la Wikipedia.
En el siglo XXI la tecnología permite que los 60 miembros del departamento podamos colaborar directamente, sin intermediarios.
Aportando ideas y exponiendo nuestros argumentos.
Y además hacerlo de forma sosegada, con tiempo para estudiar las otras propuestas, buscar referencias y elaborar nuestro discurso.</p>
<p>En resumen, colaboración y democracia en estado puro para que sea un proyecto de todos y no de los señores del cortijo ¿o no?</p>
<h1 id="heading-la-academia-de-la-ull">La Academia de la ULL</h1>
<p>Para terminar quiero aprovechar para resolver algunas dudas sobre los títulos propios, ya que he recibido varias consultas al respecto.
De hecho mucha gente no sabe que hay dos tipos de títulos.
Por si mismo, a mi eso me parece una razón más que suficiente para ser especialmente cuidadosos, evitando generar falsas expectativas.
Pero lamentablemente no todo el mundo piensa igual.</p>
<p>El primer tipo son los títulos oficiales.
Los de toda la vida.
Los que han hecho todos los que tienen una carrera universitaria para obtener el nivel académico correspondiente —licenciados, ingenieros, doctores, graduados, etc.—.
Están subvencionados, sus precios  —en las universidades públicas—  son fijados por el gobierno por medio de las tasas académicas, se pueden pedir becas para estudiarlos, pasan ciertos controles de calidad externos a la universidad y son reconocidos en toda Europa y por las administraciones públicas.
Su impartición es uno de los fines de la universidad y por eso casi todo en la ULL está construido alrededor de ellos.</p>
<p>Desde que convergimos con Europa, en lo que a educación superior se refiere, los títulos oficiales ya no los crea el gobierno.
En su lugar las universidades pueden proponer los títulos que quieran.
Es decir, que si seguimos ofertando únicamente titulaciones tradicionales de grado y máster es porque nos resistimos a salir de nuestra zona de confort.</p>
<p>En realidad sólo hay que trabajar un poco más para enviarlos a la Agencia Nacional de Evaluación de la Calidad y Acreditación (ANECA) para su verificación.
Si la evaluación es positiva, el título se convierte en oficial y se inscribe en el Registro de Universidades, Centros y Títulos.
Posteriormente es auditado periódicamente por esa misma agencia para comprobar que la universidad cumple con los compromisos adquiridos en la propuesta original.</p>
<p>Sin embargo, los títulos propios son una bestia diferente.
Por ejemplo, imaginemos que yo me levanto una mañana con la idea de que lo que hace falta en Canarias es un curso sobre el cuidado de la rana macho.
Curso que impartiré en mi tiempo libre junto a otros destacados expertos sobre el tema.
Obviamente yo me auto-proclamaría director del curso, porque para eso se me ha ocurrido tan increíble idea de negocio.</p>
<p>Uno de los problemas que tendría que enfrentar como particular es el de la gestión económica.
Sin duda mi vida sería mucho más fácil si algún tipo de gestora se encargara de asuntos como: cobrar las matrículas, pagar a los profesores o pagar facturas del material que necesitemos para impartir el curso  —por ejemplo, terrarios, insectos, ranas y sapos—.</p>
<p>Por fortuna soy profesor de la universidad, así que todos estos asuntos me los puede llevar la Fundación General de la Universidad de La Laguna (FGULL) a cambio de un 5% de los ingresos.
De hecho, gracias a mi profesión, puedo hacer que mi propia universidad ponga su marca en el curso que quiero dirigir e impartir en mis ratos libres.
Sólo necesito que la ULL se lleve un 10% adicional por gestiones y cumplir algunas normas.
Por ejemplo, que al menos un 30% de los docentes del curso también sean profesores de la universidad.
Ellos, al igual que yo, también impartirán esa docencia en su tiempo libre  —pues no forma parte de su trabajo en la ULL—  y cobrarán por ella a través de la FGULL, independientemente de su nómina.
De hecho, casi todo lo que ocurra con el curso es ajeno a la mayor parte de las estructuras de la universidad.
Así que ¿cuál es la diferencia de estos cursos respecto a los de cualquier academia?</p>
<p>Obviamente la universidad debe vigilar lo que se hace con su marca y por eso yo tendría que explicar y proponer mi idea en una memoria.
Se estudiaría en una comisión y se aprobaría en los distintos órganos de gobierno.
Al terminar el curso, tendría que hacer una memoria académica para explicar lo contentos que se han quedado los alumnos con la experiencia y una memoria económica con la liquidación correspondiente del presupuesto, para que quede claro a donde fueron destinados todos los gastos.
Pero en general estos controles son más administrativos que de otro tipo y, por lo que hemos visto en la <a target="_blank" href="/post-mortem-del-master-de-videojuegos-de-la-ull-parte-1">primera parte</a>, parece que actualmente no son especialmente rigurosos.</p>
<p>Un título propio no otorga ningún nivel académico.
Son cursos, como los que puede ofrecer cualquier academia o los que están disponibles en Internet.
Obviamente puede tener mucho valor, si detrás hay docentes de mucho prestigio o si después de un tiempo impartiéndose el mercado laboral valora de forma especialmente positiva la formación que ofrecen.
Pero también puede ocurrir todo lo contrario.</p>
<p>Personalmente me parecen una herramienta muy interesante desde la perspectiva de ofrecer formación continua complementaria a los títulos oficiales.
Por ejemplo, es indudable que mi hipotético Máster Universitario en el Cuidado de la Rana Macho sería de interés para muchos graduados con uno de estos animalillos en casa.
Pero para eso es importante no llevar a equívocos a nuestros estudiantes.
La diferencia entre títulos propios como "curso de Formación Específica en...", "Especialista Universitario en...", "Experto Universitario en..." y "Máster Universitario en..." no está más que en el número de horas lectivas.
Y además tenemos el problema que los títulos propios de máster se confunden muy fácilmente con los másteres universitarios oficiales, pues ambos utilizan la denominación "Máster Universitario en..."</p>
<p>Así que mucho ojo.
Puede que el Máster Universitario en Creación de Videojuegos y el Máster Universitario en Diseño y Desarrollo de Videojuegos no sean tan parecidos como pudiera parece a simple vista.
Uno es un título propio y el otro estamos peleando para que sea un título de la ULL reconocido oficialmente.</p>
<p><em>(Fin)</em></p>
]]></content:encoded></item><item><title><![CDATA[Post mortem del Máster de Videojuegos de la ULL (Parte 2)]]></title><description><![CDATA[¿Te has perdido la parte anterior? La tienes aquí.

Me gusta irme cada noche a la cama con la conciencia tranquila.
Ya saben, eso de haber cumplido con mis compromisos y todas esas cosas.
Así que cuando dije que me comprometía a intentar crear un tít...]]></description><link>https://jesustorres.es/post-mortem-del-master-de-videojuegos-de-la-ull-parte-2</link><guid isPermaLink="true">https://jesustorres.es/post-mortem-del-master-de-videojuegos-de-la-ull-parte-2</guid><category><![CDATA[spanish]]></category><category><![CDATA[Complaints]]></category><category><![CDATA[university]]></category><dc:creator><![CDATA[Jesús Torres]]></dc:creator><pubDate>Fri, 02 Jun 2017 00:19:17 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1635808266390/r9jXuHdc6.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>¿Te has perdido la parte anterior? La tienes <a target="_blank" href="/post-mortem-del-master-de-videojuegos-de-la-ull-parte-1">aquí</a>.</em></p>
<hr />
<p>Me gusta irme cada noche a la cama con la conciencia tranquila.
Ya saben, eso de haber cumplido con mis compromisos y todas esas cosas.
Así que cuando dije que me comprometía a intentar crear un título sobre videojuegos para el próximo curso, lo decía muy en serio.</p>
<p>Elegir hacer un título oficial, por estar convencido de que es lo mejor para la ULL y para nuestros estudiantes, añadía un elemento adicional de incertidumbre.
Pero si trabajábamos bien y rápido era posible que pasara por el proceso de verificación sin ningún contratiempo o con modificaciones menores por parte de la ANECA.
Así que hice una planificación para establecer los plazos que debíamos cumplir para llegar a tiempo.</p>
<p>Entonces ¿cómo es que nos retrasamos tanto como para que tuviéramos que ser rescatados?</p>
<blockquote>
<p>[...]El departamento optó por la tramitación larga que supone la impartición como oficial y dada la necesidad de que la Universidad de La Laguna afronte estas demandas de titulaciones específicas con rapidez y eficacia, se apoyó la iniciativa de la profesora que en el pasado dirigió esta formación como título propio de volver a editarlo.  —  Rector de la ULL, según el acta del Consejo de Gobierno de 20 de abril de 2017.</p>
</blockquote>
<h1 id="heading-el-responsable-irresponsable">El responsable irresponsable</h1>
<p>La parte más triste de toda esta historia comenzó el 17 de abril de 2017.
Ese día llevamos el Estudio de Viabilidad del nuevo título al Consejo del Departamento de Ingeniería Informática y de Sistemas para su aprobación, pero nos llevamos una sorpresa bastante desagradable.</p>
<p>Esta fue la secuencia de los acontecimientos, tal y como se la hicimos llegar al Consejo de Gobierno para que la tuviera en cuenta antes de aprobar el título propio:</p>
<ul>
<li><strong>14 de febrero</strong>, la directora del título propio presenta su título para reeditar después de 5 años, sabiendo que el departamento estaba preparando el estudio de viabilidad del oficial, sin informar en ningún momento de lo que estaba ocurriendo.</li>
<li><strong>17 de febrero</strong>, la propuesta de máster oficial se lleva al Consejo de Departamento, donde la directora del título propio es la única persona que muestra su desacuerdo  —tal y como se recoge en las actas de dicho consejo—.
No menciona que ya ha presentado la re-edición de su título propio, aunque se sospecha que la está preparando porque los estudiantes de la edición anterior —5 años atrás— por fin están recibiendo sus títulos.
Así se informa al resto del consejo.
La propuesta de título oficial no se aprueba porque el Director del Departamento insiste en que hace falta un periodo de un mes para llegar a un consenso con la directora del título propio.</li>
<li><strong>1 de marzo</strong>, tenemos una reunión con el Rector para desatascar la situación.
Obviamente es informado de todo.
El Director de la Escuela de Doctorado y Estudios de Posgrado se compromete a mediar.</li>
<li><strong>23 de marzo</strong>, hay dos propuestas muy parecidas sobre la mesa.
Una del conjunto del departamento, la otra de la directora del título propio.
Lamentablemente el Director de Departamento se niega a que se vote entre ambas; retrasando nuevamente la presentación de la propuesta definitiva.</li>
<li><strong>3 de abril</strong>, se aprueba por asentimiento en Consejo de Departamento una propuesta definitiva de consenso de título oficial que tiene el beneplácito de todas las partes.
Se comentaron los detalles de la reunión del 1 de marzo con el Rector y su interés en que el título sea una realidad este año.
El Director del Departamento no comenta nada al respecto.
<strong>Ha pasado mes y medio desde el primer intento</strong>.</li>
</ul>
<p>El título propio, que se suponía abandonado, es aprobado en Consejo de Gobierno de <strong>20 de abril</strong>.
Obviamente defendido en base a todas las supuestas ventajas que dicen que tienen los títulos propios.
Las mismas que me encargué de desmontar en la <a target="_blank" href="/post-mortem-del-master-de-videojuegos-de-la-ull-parte-1">primera parte</a>.
Esto ocurre sin tener toda la documentación en regla, pese a los problemas de gestión sufridos en la edición anterior y convirtiendo así todo el supuesto proceso de negociación con el departamento en una mera cortina de humo con el único fin de que una persona del equipo de gobierno consiguiera lo que quería.</p>
<p>Obviamente nunca fuimos informados de que esto iba a pasar.
Así que ya se pueden imaginar la cara de bobos que se nos quedó cuando en una conversación casual, el día antes, nos enteramos de que estaba en el orden del día del siguiente Consejo de Gobierno.
Y créanme si les digo que no fue nada si la comparamos con la que pusimos cuando semanas después leímos lo dicho por el Rector en el acta de ese mismo consejo.
Eso de que optamos por la tramitación larga y que por suerte vino una profesora del departamento a corregir nuestro error, se pasa por mucho de la zona de los chistes de mal gusto.</p>
<p>En mi opinión hay personas que se permiten cosas como estas porque piensan que nadie se va a enterar jamás.
Por eso es tan importante que dejemos de callarnos y que arrojemos luz sobre las cosas que pasan allí dentro.</p>
<p>Sinceramente, unos cuantos mitos sobre la universidad se vinieron a bajo y unas cuantas personas perdieron mi respeto para siempre ese día.
Como he dicho, a mi sí me gusta respetar mis compromisos y estoy orgulloso de ello.</p>
<h1 id="heading-feudalismo-universitario">Feudalismo universitario</h1>
<p>Así que el feudalismo universitario al que aludía en la <a target="_blank" href="/post-mortem-del-master-de-videojuegos-de-la-ull-parte-1">primera parte</a> es una realidad.
Es cierto que en teoría tenemos una estructura profundamente democrática.
Elegimos a nuestro Rector, a los representantes del claustro, al director de nuestro departamento y a los decanos de nuestras escuelas.
También elegimos a nuestros representantes en Consejo de Departamento o en la Junta de Escuela.
Incluso hacemos elecciones a miembros del Consejo de Gobierno  —que es el máximo órgano de gobierno universitario—.</p>
<p>Pero en el día a día la cosa es muy diferente.
Un día estamos discutiendo que tenemos un máster con pocos alumnos y alguien tiene un criterio ciertamente particular sobre cómo se debe resolver el asunto.
Entonces el director de departamento se niega en redondo porque la decisión debe ser del departamento.
¡Viva la democracia!.
Pero 3 meses más tarde el mismo director secuestra sin tapujos un Consejo de Departamento donde no le gusta la decisión que se va a adoptar democráticamente.</p>
<p>Ojo, no dudo que pensó que hacia lo mejor.
De hecho estoy convencido de que aun cree que es así.
Pero es que el director de un departamento representa a todo un colectivo, no sólo a su grupo de investigación, al área de la que es catedrático, a sus amigos o a sus propios intereses.
Si no entendemos algo tan simple, ya podemos inventarnos las formas de gobierno universitario que queramos que siempre acabaremos funcionando de la misma forma autoritaria y feudal.
Es lo que está en el ADN de la universidad y ya estamos tardando en reescribirlo.</p>
<p>Ese 17 de abril los intereses de un colectivo de entorno a 60 personas quedaron sometidos a los deseos de una sola.
Y estoy muy convencido de que nadie, absolutamente nadie más, hubiera conseguido lo mismo.
Acepto que la excusa de buscar el consenso suena muy atractiva, pero es que esa persona se había negado a colaborar por decisión propia durante los meses anteriores, mientras preparaba su propia alternativa.
Retrasar nuestro proyecto para darle una segunda oportunidad era un error de libro  —o de película, por aquello de que nunca se debe negociar con... ya saben—  como finalmente se ha demostrado.</p>
<p>Obviamente lo peor vino después.
Tras mes y medio de negociación con el que uno piensa que no solo es un mediador sino un interlocutor válido de la universidad, descubres que las familias nobles ya han urdido planes para el reino.
Sencillamente la ULL quiere ponerse una medalla sacando un título de videojuegos, una profesora que es parte del equipo tiene uno y el director de departamento, que ha sabido manejar muy bien la situación para atarnos en corto, también es gran amigo del equipo.
Todos ganan, excepto los profesores que hemos estado trabajando en el departamento para diseñar este título y que no tenemos a nadie que represente nuestros intereses.
Democracia en estado puro.</p>
<p>Ante esta patente falta de honestidad, como que me hacen mucha gracia esos discursos sobre la Academia y lo que significa ser universitario, que de vez en cuando se marcan algunos de nuestros representantes.
Claro que sí, hay que premiar el trabajo bien hecho, pero sobre todo si es de los amigos ¿verdad?.
Bueno, en realidad, si es de los amigos ni tiene que estar bien hecho ni hay que cumplir las normas.
Francamente, para alguien que si cree en esos valores, todo esto me parece una tomadura de pelo.</p>
<h1 id="heading-continuara">Continuará...</h1>
<p>Al principio no estaba seguro de que el asunto diera para tres artículos.
Pero la verdad es que hay mucho que digerir sobre nuestra universidad.
Así que mejor en pequeñas dosis.</p>
<p>Si a estas alturas alguien ha tenido el interés de pedir explicaciones a los responsables, seguro que le habrán contado una rocambolesca historia de desencuentros personales.
Obviamente nadie desmentirá los hechos porque ocurrieron tal y como los he relatado.
Pero alguien debe haber pensado que la mejor vía de escape es fingir que tantas meteduras de pata juntas no importan y que todo esto no es más que un problema de personas.</p>
<p>Mi consejo es que cambien de asesor porque todo eso lo vamos a desmontar en la tercera  —que me temo que será mucho más aburrida que las anteriores—.
En ella hablaré de los acontecimientos previos al Consejo de Departamento del 17 de abril, explicando cómo trabajamos en los 3 másteres que quiere impulsar mi departamento.
Para muchos no será algo novedoso porque hoy en día es una forma común de trabajar, pero les aseguro que tengo muchas dudas de que en la ULL se haya diseñado ningún título oficial de forma parecida.</p>
<p>Fuimos completamente abiertos y transparentes desde el principio.
Todos los compañeros, absolutamente todos, fueron animados a aportar y a participar en el debate.
La única restricción era hacer algo que pudiera ser interesante para nuestros alumnos y, por tanto, bueno para la ULL.
Obviamente al final se incorporaron los que así lo quisieron.</p>
<p><em>(Parte 3, <a target="_blank" href="/post-mortem-del-master-de-videojuegos-de-la-ull-parte-3">aquí</a>)</em></p>
]]></content:encoded></item><item><title><![CDATA[Post mortem del Máster de Videojuegos de la ULL (Parte 1)]]></title><description><![CDATA[Un post mortem de un proyecto es el proceso que se realiza para analizar los motivos de su éxito o fracaso.
Obviamente es algo que se suele realizar cuando concluye y es algo muy común en el mundo de las startups.
Cada vez que una fracasa, es frecuen...]]></description><link>https://jesustorres.es/post-mortem-del-master-de-videojuegos-de-la-ull-parte-1</link><guid isPermaLink="true">https://jesustorres.es/post-mortem-del-master-de-videojuegos-de-la-ull-parte-1</guid><category><![CDATA[spanish]]></category><category><![CDATA[Complaints]]></category><category><![CDATA[university]]></category><dc:creator><![CDATA[Jesús Torres]]></dc:creator><pubDate>Thu, 01 Jun 2017 12:45:24 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1635808271109/d0G-6a1RS.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Un <em>post mortem</em> de un proyecto es el proceso que se realiza para analizar los motivos de su éxito o fracaso.
Obviamente es algo que se suele realizar cuando concluye y es algo muy común en el mundo de las startups.
Cada vez que una fracasa, es frecuente que su CEO dedique algunas líneas  —ya sea en el blog de la empresa, en el suyo personal o en sitios como <a target="_blank" href="https://medium.com/">Medium.com</a>—  a explicar los cómo y los porqués.
En resumen, se trata de un sano acto de reflexión, para aprender de los errores cometidos, que es muy de agradecer que alguien dedique tiempo y esfuerzo en compartir.</p>
<p>Sin embargo, este <em>post mortem</em> del proyecto al que ya he dedicado casi 9 meses no va de eso.
No pretendo mostrar al resto del mundo por qué no he tenido éxito.
Sino arrojar luz sobre las aguas turbias en las que tenemos que nadar los que intentamos hacer algo en la universidad.
Porque tristemente tiene mucha razón un artículo que llegó a mis manos hace unas semanas:</p>
<blockquote>
<p>"[...]las universidades siguen reflejando con gran fidelidad las características de la sociedad feudal en la que nacieron.
"El feudalismo genera sus cabecillas y sus súbditos, que están obligados a respetar ciertos códigos ajenos al siglo XXI, como cuando te dicen ‘no te presentes a esta plaza porque ya está adjudicada’ o ‘tú no puedes publicar en esta revista hasta que yo lo haga", explica el autor de La dimisión interior (Ed Pirámide)."  —  <a target="_blank" href="https://www.elconfidencial.com/alma-corazon-vida/2014-07-07/los-8-males-del-profesor-universitario-es-uno-de-los-trabajos-mas-toxicos-que-existen_156018/">Los 8 males del profesor universitario: "es uno de los trabajos más tóxicos que existen"</a></p>
</blockquote>
<p>Que nadie dude que esto es así.
Tenemos algunos nobles.
Tenemos muchos plebeyos.
Y tenemos costumbres tan poco de nuestro tiempo como el derecho de pernada  —aunque solo en sentido figurado—.</p>
<p>Este artículo y posteriores son la crónica de los acontecimientos que he vivido en primera persona durante los últimos meses.
Aquí la dejo escrita, para vergüenza de los turbios, y para compartirla con todo aquel que quiera saber lo que realmente pasó.</p>
<p>Pónganse cómodos porque lo que viene es digno de Juego de Tronos.
Algunas cosas les parecerán increíbles pero pueden estar seguros de que lo cuento tal y como pasó.
Obviamente me he tomado la molestia de guardar cada documento que prueba que este despropósito ocurrió.</p>
<h1 id="heading-propuesta-de-un-titulo-sobre-videojuegos">Propuesta de un título sobre videojuegos</h1>
<p>A finales de julio de 2016 quien escribe estas líneas se comprometió con el equipo que gobierno de nuestra universidad a hacer una propuesta para un título relacionado con el mundo de los videojuegos.
Un estudio sin condiciones preestablecidas.
Con todas las opciones sobre la mesa: máster, experto e incluso grado.</p>
<p>El asunto parecía interesante, así que me puse a trabajar en ello.
Estudié lo que se hace en otras universidades españolas y europeas  —al menos en aquellas que tienen sus planes de estudio en inglés—.
Analicé la normativa de títulos propios y oficiales y realicé un DAFO de las distintas opciones.
Contrasté algunas cuestiones con personas de confianza de mi propio departamento y finalmente elaboré un documento con la propuesta: un máster oficial en desarrollo de videojuegos, con algo de diseño, de un año, sin especialidades ni optativas.</p>
<p>En noviembre de 2016 surgió la oportunidad idónea para compartir este documento con el resto del departamento de Ingeniería Informática y de Sistemas —volveré a esto más adelante—  y lo usamos como punto de partida para elaborar entre todos el estudio de viabilidad de un nuevo máster en desarrollo de videojuegos a propuesta del departamento.</p>
<h1 id="heading-la-ull-tuerce-el-camino">La ULL tuerce el camino</h1>
<p>Llegados a este punto hagamos un inciso y viajemos 5 meses hacia adelante  —a abril de 2017—  y escuchemos al Rector de la ULL en el Consejo de Gobierno donde pidió expresamente el voto para aprobar un título sobre videojuegos.
No el basado en la propuesta que he comentado, sino la re-edición  —nada menos que 5 años después—  de un título propio en el mismo tema, dirigido por una directora de secretariado de su equipo  —vaya casualidad—.</p>
<blockquote>
<p>"El Rector interviene confirmando la política de la Universidad de La Laguna de impulsar y potenciar la oferta de másteres oficiales, señala las ventaja que presentan los Títulos Propios en materia de profesorado al admitir la participación de profesionales que no son profesores de universidad, de flexibilidad de organización y de no computar en la carga docente del profesorado."  —  Acta del Consejo de Gobierno de 20 de abril de 2017.</p>
</blockquote>
<p>Es decir, que por lo que parece la ULL quiere títulos oficiales pero no es eso lo que se ha decidido apoyar porque los propios tienen múltiples ventajas.
Lamentablemente todas estas supuestas ventajas no son más que excusas.
Son fácilmente desmontables y, además, ninguna de ellas sirve para potenciar una educación pública y de calidad.</p>
<h2 id="heading-sobre-la-carga-docente-del-profesorado">Sobre la carga docente del profesorado</h2>
<p>Por ejemplo, que los títulos propios no computen en la carga docente del profesorado es una ventaja si eres el presidente de la CEOE.
Pero suena un poco raro en boca del Rector de una universidad pública.
Evidentemente la docencia que no computa en la carga docente se tiene que hacer fuera de la jornada laboral.
Así que lo que está diciendo es que es una ventaja montar títulos atractivos e interesantes para la sociedad a costa de hacer más horas extraordinarias, en lugar de tener gente en plantilla.
Exactamente lo que es <a target="_blank" href="https://www.eleconomista.es/economia/noticias/6292209/12/14/CEOE-propone-salarios-variables-y-mas-horas-extra.html">el sueño del presidente de la CEOE</a>.</p>
<p>Como explicaré más adelante, la duda sobre si habría que contratar profesores está fuera de lugar.
El nuevo título oficial hubiera reemplazado —junto con otros 2—  a un título oficial de mayor carga docente que iba a desaparecer.
El profesorado se comprometió a impartir la docencia y el departamento había dado su aval.
Entonces ¿dónde queda la ventaja de los títulos propios?</p>
<h2 id="heading-sobre-la-flexibilidad-de-organizacion">Sobre la flexibilidad de organización</h2>
<p>Respecto a permitir una organización más flexible  —aunque es cuestionable que, por ejemplo, un título formado por una docena de micro-asignaturas sea mejor desde el punto de vista docente—  es un error confundir las piedras que nosotros mismos nos ponemos en el camino con las limitaciones reales que marca la ley o el organismo que verifica nuestros títulos.</p>
<p>La universidad privada Ramón Llull tiene <a target="_blank" href="https://www.esade.edu/management/eng/programmes/global-strategic-management">un máster oficial</a> sin asignaturas y con periodos de formación de 3 meses en EEUU y 3 meses en China.
Sin duda algo muy distinto a lo que conocemos, que en la ULL no podríamos hacer ni como título propio, pese a su supuesta mayor flexibilidad.</p>
<p>¿Cómo lo han conseguido en la Universidad Ramón Llull si los títulos oficiales tienen tantas restricciones? Pues porque la agencia que verifica los títulos oficiales ofrece margen para hacer cualquier tipo de propuesta, siempre que esté debidamente justificada, existan precedentes en otras universidades nacionales o internacionales o la propuesta vaya avalada por un grupo académico solvente.</p>
<p>Es decir, que si en la ULL no se puede hacer lo mismo o más con los títulos oficiales que con los títulos propios es por motivos internos.
Porque nuestro reglamento de títulos oficiales es muy restrictivo.
Si el equipo de gobierno de la ULL no está de acuerdo, lo único que tiene que hacer es cambiarlo.</p>
<h2 id="heading-sobre-la-estrategia-de-copiar-lo-que-hace-tu-competidor">Sobre la estrategia de copiar lo que hace tu competidor</h2>
<p>Otra frase llamativa del Rector en el mismo Consejo de Gobierno fue la siguiente:</p>
<blockquote>
<p>"[...]Recuerda que la tramitación del Máster oficial en creación de videojuegos se inició a instancias del propio Rector, que lo pidió al departamento ante la demanda que presentaba y la urgencia de que la Universidad de La Laguna lo impartiera dada la competencia que presentaban otras entidades de educación superior presentes en la isla."  —  Acta del Consejo de Gobierno de 20 de abril de 2017.</p>
</blockquote>
<p>Precisamente por la dura competencia, si queremos tener éxito, debemos hacer algo diferente y no repetir lo que hacen los demás.
Cualquiera centro de formación y cualquier academia puede dar un curso que vale lo mismo que un título propio de la ULL.
Estos títulos no son reconocidos en ningún sitio, ni dentro ni fuera de nuestras fronteras, no dan acceso a becas ni al doctorado.
Sin embargo no hay nada en su nombre que indique claramente este hecho con el objeto de evitar que nuestros alumnos se sientan engañados.</p>
<p>Hay que trabajar muy duro para crear algo diferenciador que acabe siendo reconocido fuera de nuestro entorno más cercano, aunque el título no sea oficial.
La misma ULPGC mantiene desde hace mucho tiempo y con notable éxito un <a target="_blank" href="http://serdis.dis.ulpgc.es/~atrujillo/Experto_Videojuegos/web2017/">posgrado en videojuegos</a> y a nivel nacional se imparten decenas de títulos similares a distancia.
Entonces ¿qué sentido tiene empezar desde cero a competir en el mismo hueco donde ya hay tantos otros?</p>
<p>Obviamente estas cuestiones están discutidas exhaustivamente en la propuesta original  —que por lo que parece nadie se leyó o prefirieron ignorar—  y la conclusión fue que lo mejor para la ULL era optar por un título oficial.
Por eso fue ese el camino que escogimos en el departamento.</p>
<h2 id="heading-sobre-la-calidad-de-nuestros-titulos">Sobre la calidad de nuestros títulos</h2>
<blockquote>
<p>"[...]El departamento optó por la tramitación larga que supone la impartición como oficial y dada la necesidad de que la Universidad de La Laguna afronte estas demandas de titulaciones específicas con rapidez y eficacia, se apoyó la iniciativa de la profesora que en el pasado dirigió esta formación como título propio de volver a editarlo."  —  Acta del Consejo de Gobierno de 20 de abril de 2017.</p>
</blockquote>
<p>Lo que el Rector llama "la tramitación larga" es en realidad la única opción para una universidad pública.
Es la opción que implica que nuestro título va a ser reconocido en cualquier lugar de España y de Europa.
Es la opción que obliga a pasar una serie de filtros externos y que asegura que el título va a ser auditado cada 4 años para comprobar si estamos cumpliendo nuestros compromisos.
En definitiva, es la única opción que garantiza que el título que impartimos tiene unos mínimos de calidad.</p>
<p>En los títulos propios no se da ninguna de estas garantías.
Se puede contratar a quien se quiera y se puede hacer lo que se quiera.
Por ejemplo, se puede jugar a crear grandes expectativas para obtener muchos alumnos pero después ofrecer una formación de pena, cobrando esos profesores un sobresueldo año tras año, mientras corre la voz y desciende el número de matriculados, hasta que impartir el título ya no sea rentable.
Y por hacer eso no pasaría nada, excepto el grave daño a la imagen de la ULL.</p>
<p>Que nadie me entienda mal, seguro que hay por ahí muchísimos y magníficos profesionales dispuestos a impartir docencia en un título propio de la ULL.
Pero ojo, ser un magnífico profesional no te convierte en un buen docente.
De hecho, la universidad está llena de magníficos profesionales en su campo y sin embargo sabemos que en lo que respecta a la docencia los hay mejores y peores.</p>
<p>Claro que en un máster profesionalizante como el que hemos intentado crear debemos incorporar a los profesionales del sector.
Pero es que en los títulos oficiales disponemos de los mecanismos necesarios para hacerlo  —por medio de seminarios, <em>master classes</em>, <em>venias docendi</em> o TFM en convenio con empresas—.
Solo hay que usarlos.
La diferencia con los títulos propios es que nos vienen a auditar desde fuera.</p>
<p>Para responder a quienes duden de la importancia de estar sometidos al escrutinio de una entidad externa, habida cuenta de que la ULL debe tener sus propios mecanismos internos, sólo quiero mencionar dos situaciones que afectan al título propio sobre videojuegos que en Consejo de Gobierno del ULL de 20 de abril de 2016 se decidió re-editar.</p>
<p>La primera es que nuestro <a target="_blank" href="http://www.gobcan.es/boc/2013/110/002.html">Reglamento de Estudios Propios de Posgrado</a> dice en su Artículo 20:</p>
<blockquote>
<p><strong>Artículo 20.- Solicitud de reediciones.</strong></p>
<p>[...]</p>
<p>3. En las solicitudes de reedición se reflejarán las modificaciones que se pretendan introducir en el plan de estudios, que no deberán superar el 20% del proyecto anterior.</p>
<p>Además, se adjuntará la siguiente documentación:</p>
<p>a. La memoria académica (definitiva o provisional) del título correspondiente a la edición anterior.</p>
<p>b. La memoria económica de la edición anterior (incluyendo la cuenta de liquidación provisional o definitiva, según proceda).</p>
<p>c. Memoria conteniendo el proyecto con las modificaciones, en su caso, incorporadas.</p>
<p>d. Informe de evaluación generado a partir de los resultados del Sistema de Garantía Interna de Calidad, a los efectos de lo dispuesto en el artículo 24 del presente reglamento.</p>
</blockquote>
<p>Sin embargo la norma no se cumplió, habida cuenta de que ni en la solicitud ni en la documentación remitida al Consejo de Gobierno que lo aprobó se adjuntaban ni la memoria académica ni la memoria económica con la liquidación de la edición anterior.
La re-edición se aprobó sin ninguna información sobre como fue la vez anterior.
Es decir, los mecanismos de control internos fallaron y nadie se dio cuenta.</p>
<p>La segunda es que además es un hecho probado que aquellos estudiantes de la última edición de ese título propio  —la del curso 2011/2012—  no comenzaron a ser llamados para recoger su título hasta principios de 2017.
Es decir, que después de haber pagado 3000€  —más de lo que cuesta un título oficial—  han tenido que esperar 5 años para recibirlo.
Y no porque ese sea el tiempo normal que tarda la ULL en emitir un título sino porque la directora del mismo no había realizado hasta ahora las gestiones pertinentes.
Y sin embargo, como es un título propio, aquí no pasa nada.
El Rector de la ULL pide en Consejo de Gobierno el voto para su re-edición, aunque por no cumplir ni siquiera cumplía con el reglamento de estudios propios de posgrado.</p>
<p>Que no le quepa duda a nadie que de ninguna manera podría pasar algo por el estilo con un título oficial.
En mi opinión, si alguien tiene pensando destinar sus ahorros a mejorar su formación, mi consejo es que tenga mucho cuidado en invertirlo en quienes han demostrado en el pasado ser muy poco profesionales.</p>
<h1 id="heading-continuara">Continuará...</h1>
<p>De vuelta a noviembre de 2016, una vez decidimos que lo mejor era proponer un título oficial, sabíamos que íbamos bastante justos de tiempo.
Además yo desde el principio había adquirido el compromiso de conseguir que el título estuviera en marcha para el próximo curso y tenía claro que haría todo lo posible para que fuera así.
De hecho me reafirmé en ese compromiso en una reunión con el Rector el 1 de marzo de 2017.</p>
<p>Cómo es que el 20 de abril lo que se aprobaba en Consejo de Gobierno era un título propio presentado por un profesora, que parece que vino por fortuna a salvarnos de nuestro error, es lo que explicaré en la segunda parte.</p>
<p><em>(Parte 2, <a target="_blank" href="/post-mortem-del-master-de-videojuegos-de-la-ull-parte-1">aquí</a>)</em></p>
]]></content:encoded></item><item><title><![CDATA[El sistema de mensajería de los alumnos de Sistemas Operativos Avanzados]]></title><description><![CDATA[Hace tiempo que venía pensando en dar un cambio a la asignatura de Sistemas Operativos Avanzados.
El problema es que el tiempo no da para todo.
La idea detrás de la asignatura es que los estudiantes aprendan a desarrollar software de sistemas y para ...]]></description><link>https://jesustorres.es/el-sistema-de-mensajeria-de-los-alumnos-de-sistemas-operativos-avanzados</link><guid isPermaLink="true">https://jesustorres.es/el-sistema-de-mensajeria-de-los-alumnos-de-sistemas-operativos-avanzados</guid><category><![CDATA[Qt]]></category><category><![CDATA[spanish]]></category><category><![CDATA[university]]></category><dc:creator><![CDATA[Jesús Torres]]></dc:creator><pubDate>Mon, 05 Dec 2016 08:00:55 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/unsplash/zs-41Br0WhQ/upload/v1638557247096/xaMOgGI2ra.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hace tiempo que venía pensando en dar un cambio a la asignatura de Sistemas Operativos Avanzados.
El problema es que el tiempo no da para todo.
La idea detrás de la asignatura es que los estudiantes aprendan a desarrollar software de sistemas y para eso les propongo un proyecto que deben realizar en grupo y usando metodologías ágiles.
Yo hago de Product Owner y les doy las historias de usuario.
Ellos deben organizar los sprints y uno tras otro van haciendo el desarrollo y entregado un producto con las funcionalidades acordadas.</p>
<p>Hasta la fecha ese producto era una especie de sistema de vigilancia.
Desarrollaban un cliente que se ejecutaba en varios ordenadores donde utilizan la cámara instalada en el sistema para grabar vídeo y detectar movimiento.
Los frames con cambios son enviados junto con todo tipo de información a un servidor donde se almacenan para poder ser buscados prosteriormente.</p>
<p>La idea no está mal, pero la verdad es que me va apeteciendo un cambio en varios sentidos:</p>
<ul>
<li><p><strong>Lenguaje de programación</strong>.
Me gusta C++ y me gusta Qt.
Lo positivo de Qt es que pueden hacer interfaces gráficas, que es algo que no suelen ver los estudiantes en otras asignaturas, y que presenta problemas de concurrencia similares a los que tiene el desarrollar servicios.
Sin embargo programar con Qt no es exactamente programar en C++.
Da muchas facilidades, pero no ofrece un API moderno con toda las novedades de C++11/14/17.
Sin duda es mucho lo que nos estamos perdiendo de las últimas actualizaciones del estándar y me fastidia no darles la importancia que se merecen.
Además hay otros lenguajes para software de sistemas: Rust, Go o tal vez Elixir.
Lo que hacemos incluso se podría hacer con Java o C#, que son más demandados por las empresas locales.
Aunque cambiar de lenguaje también significa que el tiempo daría para menos.
En este punto no me termino de decidir.
Hay tantas posibilidades.</p>
</li>
<li><p><strong>Herramientas</strong>.
Obviamente cambiando de lenguaje cambian las herramientas, pero además hay algunas cosas que me gustaría incorporar.
Por ejemplo, usar <a target="_blank" href="https://cucumber.io/">Cucumber</a> para desarrollar test y hacer algo de TDD o usar <a target="_blank" href="https://cppcheck.sourceforge.net/">cppcheck</a> para el análisis estático del código.
Hace tiempo que estoy detrás de que añadan una interfaz web al servicio de vigilancia incorporando, por ejemplo, <a target="_blank" href="https://github.com/cesanta/mongoose/">mongoose</a>.
También me gustaría incorporar algo de administración de sistemas.
Por ejemplo teniendo que hacer un despliegue en condiciones en el servicios <a target="_blank" href="https://www.ull.es/servicios/stic/category/iaas/">IAAS de STIC </a>.
Y estaría encantado si pudiéramos utilizar algo de programación reactiva y orientación a los microservicios a la hora de diseñar la solución.
Este año un alumno me sugirió emplear JIRA en lugar de las <em>issues</em> de GitHub o Taiga.
Y también me pregunto si debería optar por un desarrollo más basado en los protocolos y estándares de la web que en uno donde deben diseñar sus propias soluciones desde 0.</p>
</li>
<li><p><strong>Cambiar el proyecto</strong>.
Tengo claro que hay ganas de buscar otro proyecto y abandonar el sistema de vigilancia.
De hecho, escribiendo estas líneas, se me ha ocurrido que podrían crear un sistema de registro de datos para IoT, ahora que está tan de moda.
Un servicio al que lleguen datos de todo tipo de sensores y que éstos se puedan mostrar en un panel de mando.
Sin duda tendré que explorarlo.
¿Daría esto cabida para ver algo de desarrollo de controladores de dispositivo? También tendré que explorarlo.</p>
</li>
</ul>
<p>El pasado curso di un primer paso cambiando la práctica.
Aproveché que habíamos estrenado un nuevo proyecto en la asignatura previa ese mismo año y que estos estudiantes no lo habían hecho —por haber cursado esa asignatura el año anterior— para usar ese mismo proyecto y extenderlo.
En concreto les pedí un servicio de mensajería instantánea, a lo Whatsapp, con autenticación, grupos de charla y avatares.</p>
<p>Del resultado estoy bastante contento, teniendo en cuenta que solo fueron dos meses de desarrollo usando herramientas completamente nuevas para ellos.
Dos de los grupos hicieron unos vídeos para mostrar el resultado.
Los dejo aquí porque creo que merece la pena compartirlos.</p>
<h2 id="heading-chatoso">ChatOsO</h2>
<p>El primero de los proyectos es <strong>ChatOsO</strong> de <a target="_blank" href="https://github.com/alu0100698893/ChatOsO">Alberto Martínez Chincho</a> y <a target="_blank" href="https://github.com/alu0100767452/ChatOsO">Alejandro Delgado Martel</a>.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=3N69QN0EjZI">https://www.youtube.com/watch?v=3N69QN0EjZI</a></div>
<h2 id="heading-qversare">qVersare</h2>
<p>El segundo de los proyectos es <strong>qVersare</strong> de <a target="_blank" href="https://github.com/adrianabreu/qVersare">Adrián Abreu González</a> y <a target="_blank" href="https://github.com/JRicardoPC/qVersare">Jose Ricardo Pérez Castillo</a>.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=dE3YBymie80">https://www.youtube.com/watch?v=dE3YBymie80</a></div>
]]></content:encoded></item><item><title><![CDATA[Deep Learning en el II Congreso de Estudiantes de Ingeniería Informática]]></title><description><![CDATA[Esta tarde llegó a su fin el II Congreso de Estudiantes de Ingeniería Informática de la Universidad de la Laguna con el acto de clausura y la entrega de premios. Sé que requiere un gran esfuerzo organizar una actividad como esta —algo que hay que agr...]]></description><link>https://jesustorres.es/deep-learning-en-el-ii-congreso-de-estudiantes-de-ingenieria-informatica</link><guid isPermaLink="true">https://jesustorres.es/deep-learning-en-el-ii-congreso-de-estudiantes-de-ingenieria-informatica</guid><category><![CDATA[Deep Learning]]></category><category><![CDATA[AI]]></category><category><![CDATA[spanish]]></category><category><![CDATA[meetings]]></category><dc:creator><![CDATA[Jesús Torres]]></dc:creator><pubDate>Thu, 01 Dec 2016 22:05:07 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1635808107655/6qhPgsc6M.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Esta tarde llegó a su fin el <a target="_blank" href="http://cesinf.webs.ull.es/">II Congreso de Estudiantes de Ingeniería Informática de la Universidad de la Laguna</a> con el acto de clausura y la entrega de premios. Sé que requiere un gran esfuerzo organizar una actividad como esta —algo que hay que agradecer a <a target="_blank" href="https://twitter.com/nchbot">José Ignacio Estévez</a>, que me consta que se ha dejado la piel, y a su equipo de voluntarios— pero sin duda creo que es muy enriquecedora para los estudiantes.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1635808105994/Aitpvmrsp.jpeg" alt="Cartel del II Congreso de Estudiantes de Ingeniería Informática" class="image--center mx-auto" /></p>
<p>Este congreso permite a los estudiantes que lo han querido exponer su trabajo —doy fe de que los hay muy buenos y algunos incluso podrían tener impacto a nivel regional— y los demás han podido ver lo que hacen sus compañeros; con apenas un curso o dos por delante de ellos. A mí eso me parece algo tremendamente motivador que incluso puede llevar a despertar algunas vocaciones.</p>
<p>Además, este año hemos tenido concurso de videojuegos y 4 ponentes de primer nivel en ese tema: <a target="_blank" href="https://twitter.com/danielblanco3d">David Blanco</a>, <a target="_blank" href="https://twitter.com/Notnasiul">Luis Antón</a> (<a target="_blank" href="https://www.facebook.com/SaveAsociacion">SAVE</a>), <a target="_blank" href="https://twitter.com/TonioCabrera">Antonio Cabrera</a> (<a target="_blank" href="https://tgx.es/">TGX.es</a>) e <a target="_blank" href="https://twitter.com/isidro_quintana">Isidro Quintana</a> (<a target="_blank" href="http://promineostudios.com/">Promineo Studios</a>). Es indudable que el tema de los videojuegos levanta pasiones entre los estudiantes. Así que parece evidente que en la ULL deberíamos dar los pasos necesarios para cubrir esa demanda. En esta ocasión estudiantes y profesores hemos tenido la oportunidad de escuchar lo que estos profesionales tenían que contarnos y de preguntarles por su trabajo. El debate fue tremendamente interesante y yo salí con algunas buenas ideas en el bolsillo.</p>
<p>Por mi parte, tuve la suerte de que me invitaran a dar una charla sobre <a target="_blank" href="http://deeplearning.net/">Deep Learning</a>, un campo en el que trabajo —o lo intento— últimamente. Espero que haya gustado. Y tal y como prometí, aquí dejo la presentación que utilicé.</p>
<div class="hn-embed-widget" id="deep-learning-getting-started-skynet"></div><p> </p>
<p>Esperemos que la <a target="_blank" href="http://www.ull.es/view/centros/etsii/Inicio/es">Escuela Superior de Ingeniería y Tecnología de la ULL</a> se anime el próximo año a promover la organización de una tercera edición de este congreso de estudiantes.</p>
]]></content:encoded></item><item><title><![CDATA[La ULL estrena Adobe Connect: ¿Qué fue del compromiso con el software libre?]]></title><description><![CDATA[Actualización de 5 de abril de 2016: Finalmente los responsables de la UDV se animaron a informar a los asistentes a la sesión formativa de todas las herramientas de videoconferencia disponibles oficialmente en la ULL.
Sin embargo, la comparativa mos...]]></description><link>https://jesustorres.es/la-ull-estrena-adobe-connect-que-fue-del-compromiso-con-el-software-libre</link><guid isPermaLink="true">https://jesustorres.es/la-ull-estrena-adobe-connect-que-fue-del-compromiso-con-el-software-libre</guid><category><![CDATA[spanish]]></category><category><![CDATA[Complaints]]></category><category><![CDATA[university]]></category><dc:creator><![CDATA[Jesús Torres]]></dc:creator><pubDate>Mon, 04 Apr 2016 00:09:29 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/unsplash/smgTvepind4/upload/v1638557132011/O_w9tyQ73C.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em><strong>Actualización de 5 de abril de 2016</strong>: Finalmente los responsables de la UDV se animaron a informar a los asistentes a la sesión formativa de todas las herramientas de videoconferencia disponibles oficialmente en la ULL.</em>
<em>Sin embargo, la <a target="_blank" href="http://www.slideshare.net/cjgonza/videoconferencia-para-docencia">comparativa mostrada</a> durante la sesión se basa en otra de 2014 y solo tiene en cuenta Skype y los servicios actualmente soportados por la ULL, por lo que no sirve para concluir que la nueva incorporación es la mejor de las diversas alternativas actuales, libres o privativas.</em>
<em>De hecho, prácticamente todos los supuestos inconvenientes de BigBlueButton según esa comparativa parece que están resueltos en un software derivado y desarrollado por universidades denominado <a target="_blank" href="http://mconf.org/">MConf</a>.</em>
<em>Actualmente RedIRIS ofrece a la comunidad un <a target="_blank" href="https://mconf.rediris.es/">servicio de videocoferencia</a> en fase de piloto que se basa en él.</em></p>
<hr />
<p>Este es artículo es un extracto y ampliación de las principales ideas de un correo que envié el pasado jueves a la lista de correo de la <a target="_blank" href="https://listas.osl.ull.es/wws/arc/plataforma">Plataforma de Software Libre de la ULL</a>.
Como dije entonces, este artículo es más que nada para liberar algo de frustración, puesto que parece que poco se puede hacer a estas alturas de la película sobre el tema que voy a tratar.</p>
<p>Como suele pasar, todo empieza con un correo recibido el mismo jueves 31 de marzo:</p>
<blockquote>
<p>"El próximo lunes 4 de abril de 10 a 12 de la mañana la Unidad de Docencia Virtual celebrará en la sala de reuniones del Vicerrectorado de Docencia una sesión formativa sobre Adobe Connect, un sistema de videoconferencia de especial interés para las titulaciones semipresenciales y online que podrán utilizar con los estudiantes.
Sería conveniente la asistencia del profesorado de nuestro máster."</p>
</blockquote>
<p>¿Mi primer pensamiento? Que parece que ahora tenemos Adobe Connect cuando hasta hace poco la ULL no tenía licencias de ese producto.
¿Era tan urgente hacer esto que ha sido de lo primero que se ha hecho para modernizar el servicio?</p>
<p>Excepto que alguien se haya detenido a comparar sus características técnicas y haya concluido que algunas son tan interesantes y tan necesarias que está más que justificada la adquisición de Adobe Connect, <strong>a mí me parece un paso atrás en toda regla en la estrategia que se estaba siguiendo hasta ahora</strong>.
A fin de cuentas, es cierto que en la comunidad de software libre de la ULL nos hemos lamentado muchas veces de que el compromiso de la institución con el software libre nunca nos haya llevado a la "última frontera", es decir, a migrar Offices y Windowses.
Pero eso no implica que no se haya andado un largo camino creando cierta cultura de que <strong>hay que ponderar las distintas opciones, de que libre es preferible a privativo y de que si finalmente hay que comprar licencias, que sean las justas y necesarias para lo que se pretende hacer</strong>.
Por eso, por ejemplo, no hay licencias de Adobe Acrobat para todos —ahora no puedo estar seguro pero al menos antes era así—  sino solo para aquellos servicios que no tienen suficiente con las características de programas como PDFCreator.</p>
<h1 id="heading-tirando-del-historico">Tirando del histórico</h1>
<p>Tengo mala memoria, así que puedo estar equivocado, pero el asunto del Adobe Connect en la ULL viene de lejos.
Al menos me suena que se hablaba de él en los inicios de <a target="_blank" href="https://www.youtube.com/user/UniversidadLaLaguna">ULLmedia</a> o incluso antes.
Recuerdo que cuando salía el tema intentaba hacer proselitismo de las alternativas libres, como he hecho siempre.
La verdad es que no sé porque finalmente no terminó de cuajar la idea en esa época.
¿Tal vez no había suficiente presupuesto?</p>
<p>Ya más reciente, <strong>cuando yo formaba parte de la OSL y <a target="_blank" href="http://jmargu.webs.ull.es/">Jorge Martín</a> de la UDV, volví tener que tratar el tema para discutir alternativas a las distintas aplicaciones privativas que ofertaban a la ULL</strong>.
Por ejemplo, la <a target="_blank" href="http://www.uned.es/">UNED</a> tenía su propia <a target="_blank" href="http://ieeexplore.ieee.org/xpls/abs_all.jsp?arnumber=6142995&amp;tag=1">plataforma de videoconferencia</a> y se ofrecía a compartirla.
En la <a target="_blank" href="http://www.uca.es/es/">UCA</a> habían probado Adobe Connect, pero finalmente optaron por invertir el dinero de las licencias en unas becas con las que <a target="_blank" href="http://rodin.uca.es/xmlui/handle/10498/9778">echar a andar Access Grid</a>.
También estaban <a target="_blank" href="http://openmeetings.apache.org/">OpenMeeting</a>, <a target="_blank" href="http://bigbluebutton.org/">BigBlueButton</a> e <a target="_blank" href="http://isabel.morfeo-project.org/lng/es/">Isabel</a>.
De este último derivaba un producto comercial denominado GlobalPlaza del que ya no encuentro referencias.</p>
<p>Esto fue en 2011 y <strong>fruto de esa coordinación entre servicios finalmente se apostó por <a target="_blank" href="http://bigbluebutton.org/">BigBlueButton</a></strong>.
Porque aunque soluciones como Adobe Connect o Cisco WebEx tienen un coste ridículo para lo que es el presupuesto TIC de la ULL, <strong>la prioridad era usar software libre siempre que fuera posible</strong>.
Y además <strong>teníamos muy claro que cada euro contaba porque podía necesitarse para cosas más urgentes</strong>.</p>
<p>Sé que a lo largo de los últimos años se trabajó la integración con <a target="_blank" href="https://moodle.org/">Moodle</a> y se ofreció formación al profesorado.
Sin embargo, en 2016 <strong>¿dónde ha quedado ese trabajo?</strong>, ¿por qué la opción es pagar y ofrecer acceso a una herramienta privativa?, <strong>¿o es que el compromiso de la ULL con el software libre no compromete por igual a todos los servicios relacionados con las TIC?</strong></p>
<h1 id="heading-el-estilo-universidad-de-cadiz">El estilo Universidad de Cadiz</h1>
<p>Antes de terminar me gustaría dedicar unas palabras al estilo <a target="_blank" href="http://www.uca.es/es/">UCA</a> de hacer las cosas, que ya mencioné anteriormente:</p>
<blockquote>
<p>"En la UCA habían probado Adobe Connect pero finalmente optaron por invertir el dinero de las licencias en unas becas con las que echar a andar Access Grid."</p>
</blockquote>
<p>Cuando en 2011 me lo contó el director de su <a target="_blank" href="http://servicio.uca.es/softwarelibre">OSL</a> a mí lo que me dio fue envidia.
Porque el coste de la solución para la <a target="_blank" href="http://www.uca.es/es/">UCA</a> no solo era el coste de Adobe Connect sino también el de los diversos servidores Windows donde debe correr para dar servicio a toda la comunidad universitaria.</p>
<p>No sé lo que habrá pasado en la <a target="_blank" href="http://www.uca.es/es/">UCA</a> en estos años.
Hace mucho que <a target="_blank" href="https://directorio.uca.es/cau/directorio.do?PERSONA=Manuel,Palomo,Duarte,D137">Manuel Palomo</a> no es director de su <a target="_blank" href="http://servicio.uca.es/softwarelibre">OSL</a> y seguro que han cambiado de equipo de gobierno en al menos una ocasión desde entonces.
Pero eso no es lo importante.
<strong>Lo crucial, es lo audaces que fueron entonces</strong>.</p>
<p><strong>¿Por qué aquí no se puede hacer algo parecido en lugar de correr a pagar licencias?</strong> Tengamos en cuenta que <strong>en esto de introducir el uso del software libre es fundamental aprovechar la oportunidad para minimizar la resistencia</strong>.
<strong>¿Quién migrará mañana</strong> —otra vez— <strong>a una solución libre cuando los técnicos y los usuarios estén acostumbrados a trabajar con Adobe Connect?</strong></p>
<p>Como he dicho, <strong>esta me parece una decisión muy poco meditada</strong>.
Otra oportunidad de apoyar el software libre que dejamos que se nos escurra entre los dedos por no tomar medidas para asegurarnos de que los distintos servicios funcionan alineados con los intereses generales de la institución.</p>
]]></content:encoded></item><item><title><![CDATA[Aprender Qt con tutoriales de Youtube]]></title><description><![CDATA[Última actualización: 20 de noviembre de 2021.

Debido a que he escrito algunos artículos sobre Qt que utilizo como referencia en mis clases, muchas personas se han puesto en contacto conmigo preguntando por material con el que seguir aprendiendo ace...]]></description><link>https://jesustorres.es/aprender-qt-con-tutoriales-de-youtube</link><guid isPermaLink="true">https://jesustorres.es/aprender-qt-con-tutoriales-de-youtube</guid><category><![CDATA[Qt]]></category><category><![CDATA[tutorials]]></category><category><![CDATA[spanish]]></category><category><![CDATA[ull-esit-soa]]></category><dc:creator><![CDATA[Jesús Torres]]></dc:creator><pubDate>Wed, 14 Oct 2015 14:58:56 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1635808186991/IG1QRRgYW.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong><em>Última actualización:</em></strong> <em>20 de noviembre de 2021.</em></p>
<hr />
<p>Debido a que he escrito algunos artículos sobre <a target="_blank" href="http://www.qt.io/">Qt</a> que utilizo como referencia en mis clases, muchas personas se han puesto en contacto conmigo preguntando por material con el que seguir aprendiendo acerca de este fantástico <em>framework</em>. En varias ocasiones me he puesto a hacer recopilación del material que considero más interesante y al final me he acabado preguntando por qué no mantener, lo más actualizado posible, un artículo sobre este tema que pueda remitir cada vez que alguien me pregunte por esta cuestión. Bien, pues dicho y hecho, este pretender ser ese artículo.</p>
<h1 id="heading-en-espanol">En Español</h1>
<p>Obviamente, la mayor parte del material que se puede conseguir en Internet está en inglés. Pero voy a empezar por los vídeos en español porque seguramente sean más accesibles para quienes estén interesados en este tema.</p>
<p>El primero es un completo curso de Qt que trata los aspectos más comunes: desarrollo de una aplicación con interfaz gráfica de usuario, señales y slots, recursos y los tipos y contenedores usados con mayor frecuencia.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=UeBDREl7A28&amp;list=PLFB1CB34F174FAD08">https://www.youtube.com/watch?v=UeBDREl7A28&amp;list=PLFB1CB34F174FAD08</a></div>
<p> </p>
<p>Este curso básico se complementa con un curso posterior de nivel intermedio:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=izxA3tkGVi0&amp;list=PLHNkID2PAnJmYaScPDAwPmERoEbibSel2">https://www.youtube.com/watch?v=izxA3tkGVi0&amp;list=PLHNkID2PAnJmYaScPDAwPmERoEbibSel2</a></div>
<p> </p>
<p>Hay que tener en cuenta que ambos cursos ya tienen sus años. En la actualidad tenemos Qt 6, pero el primero de los cursos enseña Qt 4 y en el segundo Qt 5. Muchos de los conceptos siguen siendo válidos, porque a nivel básico e intermedio Qt no ha cambiado demasiado, pero es posible que las diferencias en la interfaz programas utilizados confundan un poco.</p>
<p>El siguiente curso de Qt 5 no es tan completo como el anterior, pero puede complementarlo en algunos temas concretos a los anteriores.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=bpQCo8Bpuu8&amp;list=PLof56DT2gOV0nArJCsADAZ3R9nQ4d9Zo1">https://www.youtube.com/watch?v=bpQCo8Bpuu8&amp;list=PLof56DT2gOV0nArJCsADAZ3R9nQ4d9Zo1</a></div>
<p> </p>
<p>Qt se programa en C++. Sin embargo, el <em>framework</em> trae muchísimas herramientas que empleadas adecuadamente lo hacen muy parecido a Java, C# y lenguajes similares. Si aun así alguien prefiere probarlo usando un lenguaje diferente, nada mejor que hacerlo con Python y Qt for Python:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=8dlvGIlc6pA&amp;list=PLi4GWwqkkQgXKkenvxjebkGSgnSo5FFog">https://www.youtube.com/watch?v=8dlvGIlc6pA&amp;list=PLi4GWwqkkQgXKkenvxjebkGSgnSo5FFog</a></div>
<p> </p>
<p>A continuación veremos algunos tutoriales más pero en inglés.</p>
<h1 id="heading-en-ingles">En inglés</h1>
<p>En inglés de lo mejorcito es este completísimo tutorial —con diferencia— que abarca prácticamente todo lo que incluye Qt:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=6KtOzh0StTc&amp;list=PL2D1942A4688E9D63">https://www.youtube.com/watch?v=6KtOzh0StTc&amp;list=PL2D1942A4688E9D63</a></div>
<p> </p>
<p>Y que se complementa perfectamente con los libros <a target="_blank" href="https://qmlbook.github.io/">Qt5 Cadaques</a> y <a target="_blank" href="https://www.qt.io/product/qt6/qml-book">Qt6 QML Book</a> —aún incompleto— dedicados en exclusiva a explicar todos los entresijos de <a target="_blank" href="https://es.wikipedia.org/wiki/QML">Qt QML</a>.</p>
<p>En los primeros vídeos se puede ver que descarga e instala Qt 4, pero en los últimos utiliza Qt 6, porque el autor no ha dejado de actualizarlos desde que comenzó a hacerlos. Además, tiene varios <a target="_blank" href="https://www.udemy.com/user/bryan-cairns/">cursos en Udemy</a>.</p>
<p>Si los 224 vídeos de la lista de reproducción anterior son muchos, siempre se puede optar por la siguiente lista, que va mucho más al grano:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=8opfd5aYkq8&amp;list=PLS1QulWo1RIZjrD_OLju84cUaUlLRe5jQ">https://www.youtube.com/watch?v=8opfd5aYkq8&amp;list=PLS1QulWo1RIZjrD_OLju84cUaUlLRe5jQ</a></div>
<p> </p>
<p>Aparte del desarrollo de una GUI, también toca temas como el uso de bases de datos SQL. Como inconvenientes: explica Qt 5, no entra en el uso de hilos ni del módulo de comunicaciones en red, ni tampoco se detiene a tratar exhaustivamente cada uno de los tipos de controles gráficos soportados.</p>
<p>Por otro lado, si todo esto resulta demasiado aburrido ¿por qué no aprender Qt desarrollando un videojuego?. Eso es precisamente lo que nos enseña el autor del siguiente tutorial:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://youtu.be/8ntEQpg7gck?list=PLMgDVIa0Pg8WrI9WmZR09xAbfXyfkqKWy">https://youtu.be/8ntEQpg7gck?list=PLMgDVIa0Pg8WrI9WmZR09xAbfXyfkqKWy</a></div>
<p> </p>
<p>Además, aprovecha para explicar el <a target="_blank" href="http://doc.qt.io/qt-5/graphicsview.html">Graphic View Framework</a> de Qt; un componente que lamentablemente se suele dejar de lado en muchos otros cursos. Dicho <em>framework</em> usa un árbol <a target="_blank" href="https://en.wikipedia.org/wiki/Binary_space_partitioning">BSP</a> para manejar en tiempo real escenas con un gran número de elementos gráficos 2D, tal y como se necesita al desarrollar cualquier videojuego.</p>
<p>Y eso es todo. Tal y como manifesté al principio, iré actualizando esta entrada según vaya encontrando nuevos materiales.</p>
]]></content:encoded></item><item><title><![CDATA[IOMMU: Primer asalto]]></title><description><![CDATA[La IOMMU es una unidad de algunas CPU modernas que, entre otras cosas, permite que una máquina virtual pueda tener acceso directo y exclusivo a ciertos dispositivos del sistema. Es decir, sin que el dispositivo tenga que ser emulador o virtualizado y...]]></description><link>https://jesustorres.es/iommu-primer-asalto</link><guid isPermaLink="true">https://jesustorres.es/iommu-primer-asalto</guid><category><![CDATA[desktop]]></category><category><![CDATA[Linux]]></category><category><![CDATA[Windows]]></category><category><![CDATA[spanish]]></category><category><![CDATA[computer architecture]]></category><dc:creator><![CDATA[Jesús Torres]]></dc:creator><pubDate>Tue, 06 Oct 2015 08:00:49 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/unsplash/EuRszFvB6kY/upload/v1638552946119/FZrJFBsAZ.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>La IOMMU es una unidad de algunas CPU modernas que, entre otras cosas, permite que una máquina virtual pueda tener acceso directo y exclusivo a ciertos dispositivos del sistema. Es decir, sin que el dispositivo tenga que ser emulador o virtualizado y prácticamente sin ninguna intervención del sistema que la hospeda. Como así se puede acceder con el máximo rendimiento a dicho dispositivo desde una máquina virtual, la primera vez que oí hablar de esta tecnología fue con la intención de dar acceso a conjuntos de GPU a aplicaciones que corría en máquinas virtuales en la nube —concretamente usando el <a target="_blank" href="http://en.wikipedia.org/wiki/Xen">hipervisor Xen</a>— con el objeto de que pudieran acelerar ciertas operaciones intensivas de cálculo.</p>
<p>Desde un punto de vista personal, hace 6 meses que decidí reinstalar mi ordenador después de tenerlo guardado un año a causa de una mudanza que parecía que nunca iba a terminar. En aquel momento tuve la idea de aprovechar la ocasión para intentar utilizar esta tecnología con el objeto de crear un sistema de escritorio virtualizado. Pero, como suele ocurrir con la tecnología recién llegada, las cosas suelen ser más sencillas de decir que de hacer.</p>
<h1 id="heading-iommu">IOMMU</h1>
<p>Todas CPU modernas de propósito general disponen de una unidad de gestión de la memoria principal (MMU). Una de sus funciones es traducir las direcciones de memoria manejadas por la CPU —generalmente llamadas direcciones virtuales— en las direcciones físicas que verán los módulos de la memoria principal cuando sean accedidos. Esto permite a los sistemas operativos modernos aislar a unos procesos de otros, como si para cada uno generasen la ilusión de que están solos en el sistema y que toda la memoria es solo para ellos.</p>
<p><a target="_blank" href="https://commons.wikimedia.org/wiki/File:Virtual_address_space_and_physical_address_space_relationship.png"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1637025233568/YpEX44G93.png" alt="Relación entre espacio de dirección virtual y espacio de direcciones físico" class="image--center mx-auto" /></a></p>
<p>Por otro lado la memoria RAM no es lo único que puede ser accedido mediante el direccionamiento de la memoria principal. Muchos dispositivos de E/S ocupan rangos de direcciones de memoria, de tal forma que cuando se accede a dichas zonas realmente se está accediendo a los dispositivos en cuestión. Es decir, que haciendo uso de la MMU es perfectamente posible que un proceso tenga acceso directo a un dispositivo. De hecho este es uno de los aspectos sobre los que se sustenta <a target="_blank" href="http://es.wikipedia.org/wiki/Direct_Rendering_Infrastructure">DRI</a> —acrónimo de <a target="_blank" href="http://es.wikipedia.org/wiki/Direct_Rendering_Infrastructure">Direct Rendering Infrastructure</a>— una tecnología clave para que las aplicaciones gráficas en sistemas basados en <a target="_blank" href="http://es.wikipedia.org/wiki/X.Org_Server"><em>X.Org</em></a> puedan acceder de manera directa al hardware de vídeo, mejorando así el rendimiento de dichas aplicaciones.</p>
<p>Sin embargo, las facilidades ofrecidas por la MMU no son suficientes para todos los dispositivos. Algunos buses de E/S —como PCI, PCIe, FireWire y Thunderbolt, entre otros— soportan algún tipo de acceso directo a memoria (<a target="_blank" href="http://es.wikipedia.org/wiki/Acceso_directo_a_memoria">DMA</a>). Es decir, que los dispositivos pueden enviar o recibir datos desde la memoria principal sin intervención de la CPU. Esta es una característica muy interesante porque permite a la CPU ocuparse de otras tareas mientras tienen lugar las operaciones de E/S programadas. El problema es que se debe indicar a los dispositivos en qué direcciones físicas de la memoria principal deben depositar los datos, algo imposible para cualquier proceso, ya que estos solo conocen y manipulan direcciones virtuales. Sin saber en qué direcciones físicas las transformará la MMU, es imposible que un proceso le indique a un dispositivo de E/S que haga una operación con acceso directo a memoria. Es aquí donde entra en juego la IOMMU, que fue introducida en 2011 en los procesadores de la familia x86.</p>
<p><a target="_blank" href="https://commons.wikimedia.org/wiki/File:MMU_and_IOMMU.svg"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1637024495224/sNnDm3Joh.png" alt="MMU e IOMMU" class="image--center mx-auto" /></a></p>
<p>La IOMMU es una unidad de gestión de la memoria, similar a la MMU, que se sitúa entre un bus de E/S y la memoria. Al igual que la MMU mapea las direcciones virtuales visibles para la CPU en las direcciones físicas visibles para la memoria, la IOMMU traduce las direcciones virtuales visibles para los dispositivos de E/S en direcciones físicas de la memoria. Lo que permite, entre otras cosas:</p>
<ul>
<li><p>Proteger la memoria de dispositivos defectuosos y de ataques de DMA. En un sistema sin IOMMU un dispositivo defectuoso, malicioso o mal programado —ya sea por el firmware interno o por el software del sistema— que se conecte a través de un bus que soporte DMA puede acabar leyendo o escribiendo zonas vitales de la memoria; provocando la corrupción de la información o comprometiendo el sistema. Por el contrario, en sistemas con IOMMU el sistema operativo tiene control exclusivo sobre la MMU y la IOMMU, pudiendo confinar así a cada proceso y cada dispositivo a su propio espacio de memoria.</p>
</li>
<li><p>En sistemas virtualizados, ofrecer acceso directo a dispositivos físicos desde las máquinas virtuales —lo que se denomina <em>device passthrough</em>—. Gracias al uso de la MMU el sistema operativo del anfitrión puede hacer que dispositivos físicos concretos aparezcan en el espacio de memoria virtual que hace de memoria física de la máquina virtual. Si estas direcciones son comunicadas por el sistema operativo de la máquina virtual a un dispositivo con DMA como origen o destino de una transferencia, sin IOMMU habrá problemas porque no son auténticas direcciones físicas que dicho dispositivo pueda usar para acceder a la memoria. Sin embargo, con IOMMU las direcciones de memoria utilizadas por el dispositivo durante la transferencia se mapearán a las direcciones físicas correctas.</p>
</li>
</ul>
<p>Es esta última ventaja de la IOMMU la que me interesa. Ya antes de este proyecto personal, la IOMMU me facilitó usar <a target="_blank" href="https://www.vagrantup.com/"><em>Vagrant</em></a> para crear un entorno reproducible para desarrollar software que hacía uso de dispositivos hardware específicos —una capturadora BlackMagick—. Y ahora me permite plantearme el compartir la GPU con una máquina virtual con el fin de crear un sistema de escritorio virtualizado, con una mínima pérdida de rendimiento respecto al sistema anfitrión.</p>
<h1 id="heading-el-golpe-con-la-realidad">El golpe con la realidad</h1>
<p>Y menudo golpe. Las piezas del ordenador las escogí en 2011, justo cuando empezaba a surgir esta tecnología. Así que si bien he descubierto posteriormente que muchos de los componentes que elegí no eran lo mejor para este propósito, también es verdad que las circunstancias no me hubieran permitido hacerlo mucho mejor.</p>
<h2 id="heading-cpu">CPU</h2>
<p>El soporte de IOMMU lo ofrece la CPU y —excepto por unos pocos modelos anteriores de Intel— en la familiar x86 surge masivamente con los procesadores <a target="_blank" href="https://es.wikipedia.org/wiki/Sandy_Bridge">Sandy Bridge</a>, bajo la denominación de VT-d (Intel Virtualization Technology for Directed I/O). Lamentablemente, no todos los modelos tienen soporte. Por ejemplo, prácticamente ningún procesador Intel Core i3 lo tiene. Además, dentro de una misma familia es posible que modelos concretos tampoco lo tengan. Ese fue mi caso, que adquirí un Intel Core i7 2600K con la absurda esperanza de jugar un poco a <em>overclockearlo</em>, con un tiempo del no disponía —la letra K indica que el multiplicador de frecuencia de la CPU está desbloqueado, lo que los hace ideales para el <em>overclocking</em>— . Lamentablemente, ninguno de los modelos desbloqueados de la familia Sandy Bridge en aquel entonces soportaban VT-d. Esto, aunque común, no es una norma, pues posteriormente ha ido apareciendo algunos procesadores K con soporte VT-d tanto en Sandy Bridge como en familias posteriores.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1637024495236/dAqVzDkHV_.png" alt class="image--center mx-auto" /></p>
<p>Incluso teniendo una CPU con soporte hay que tener presente que algunos modelos tienen sus singularidades. Por ejemplo, activar IOMMU en un procesador Sandy Bridge puede ocasionar una <a target="_blank" href="https://web.archive.org/web/20160303212259/http://permalink.agmne.org/gmane.comp.networking.dpdk.devel/7409">caída importante del rendimiento que no se aprecia en otras familias de procesadores Intel</a>. Por mi parte, acabé sustituyendo la CPU por otra Intel Core i7 3770 —que es un procesador de la familia Ivy Bridge—.</p>
<h2 id="heading-placa-madre">Placa madre</h2>
<p>Lo siguiente es tener una placa madre con el chipset adecuado de un fabricante que no haya desactivado esta funcionalidad. <a target="_blank" href="https://en.wikipedia.org/wiki/List_of_IOMMU-supporting_hardware">Wikipedia indica</a> que chipsets como Q87, Q77, Q35, X38, X48 Q45, etc. lo soportan oficialmente, pero también placas madre que tienen chipsets diferentes, como: Z68, Z77, Z87, Z97, X58 o Q67. Para complicar un poco más el asunto, el soporte de VT-d puede ser desactivado voluntariamente por el fabricante. Esto hace que sea posible comprar una CPU y una placa madre con un chipset que soporte VT-d, pero que no nos funcione, que funcione a medias porque el fabricante solo ha hecho parte de su trabajo o que empiece a funcionar meses más tarde, cuando nos acordemos de actualizar la BIOS.</p>
<p>Ante esta situación, el comentado más escuchado en los foros era intentarlo y dejar constancia de cara a la comunidad de si había funcionado o no y en qué condiciones. Así los que lleguen después sabrán qué hardware comprar con la seguridad de que a alguien le ha funcionado. En mi caso había comprado una ASUS P8Z68-V cuyo chipset —el Z68—  supuestamente no soporta IOMMU. Sin embargo, un día actualicé la BIOS a la última versión tras haber leído un comentario en sentido positivo y comenzó a funcionar. A diferencia de otras BIOS, no puedo activar VT-x —el soporte de virtualización estándar— sin activar VT-d, pero tampoco me voy a quejar por eso.</p>
<h2 id="heading-dispositivo">Dispositivo</h2>
<p>En principio podemos hacer <em>passthrough</em> de cualquier dispositivo PCI o PCIe. De hecho mis primeros intentos fueron con una pareja de tarjetas capturadoras BlackMagick DeckLink y no tuve ningún problema. Pero el asunto se complica cuando queremos hacer lo mismo con tarjetas gráficas porque en ellas tenemos que cargar con el legado de las viejas VGA. Tanto es así, que a este tipo de <em>passthrough</em> se le ha dado su propio nombre: <em>VGA passthrough</em>. Y hay software de virtualización como VirtualBox que si bien soportan el <em>PCI passthrough</em> no soportan el caso particular de hacerlo con tarjetas gráficas. En todo caso, dejaré la problemática particular de las tarjetas gráficas para un artículo posterior.</p>
<p>Solo adelantaré que el <em>passthrough</em> de las gráficas integradas de Intel (IGD) no es una posibilidad —las gráficas incluidas en las <a target="_blank" href="https://es.wikipedia.org/wiki/AMD_Accelerated_Processing_Unit">APU</a> de AMD se parecen más a las gráficas discretas, no obstante, actualmente tampoco está muy claro si se puede hacer con ellas—. Además, no quitaremos muchos problemas si optamos por no usar la IGD ni para mostrar el escritorio del ordenador anfitrión.</p>
<p>Si necesitamos utilizar la IGD en el ordenador anfitrión, nuestra vida será algo más fácil si nos aseguramos de que las gráficas discretas que vamos a utilizar tienen una ROM que soporta UEFI —es decir, pueden emplearse en el arranque si recurrir a la vieja interfaz VGA—. En mi caso me vi obligado a cambiar  —sintiéndolo mucho, porque mi vieja gráfica aún me servía perfectamente— una GeForge GTX 560 Ti por una GTX 950, dado que el fabricante decidió en su momento no actualizar a UEFI toda la serie 500.</p>
<h2 id="heading-sistema-operativo">Sistema operativo</h2>
<p>Voy a utilizar Linux. <em>KVM</em> o <em>Xen</em>, VFIO, <em>QEMU</em>, <em>libvirt</em> y <em>virt-manager</em>. Muchas son las tecnologías del ecosistema Linux que se ven involucradas en este proyecto. Algunas de ellas carecían de cierta madurez respecto al soporte IOMMU cuando comencé, pero hoy ya no es así. Funcionan perfectamente y existen decenas de foros y blogs en la red donde se explica cómo usarlas. Lo único es que aún no se puede hacer en tan solo un par de clics.</p>
<h1 id="heading-referencias">Referencias</h1>
<ul>
<li><p><a target="_blank" href="https://en.wikipedia.org/wiki/IOMMU">IOMMU</a> — Wikipedia</p>
</li>
<li><p><a target="_blank" href="https://en.wikipedia.org/wiki/List_of_IOMMU-supporting_hardware">List of IOMMU-supporting hardware</a>  — Wikipedia</p>
</li>
</ul>
<p><em>(Parte 2,</em> <a target="_blank" href="/iommu-la-maldicion-de-la-vga"><em>aquí</em></a><em>)</em></p>
]]></content:encoded></item><item><title><![CDATA[Monitoriza tu sistema con estilo usando Conky]]></title><description><![CDATA[Encabeza este artículo el tema Conky Colors

Ordenador recién instalado con Kubuntu 15.04, shell y terminal bien configurada, llega la hora de buscar una herramienta para monitorizar el sistema y estar, en lo posible, al tanto de cuando le estoy pidi...]]></description><link>https://jesustorres.es/monitoriza-tu-sistema-con-estilo-usando-conky</link><guid isPermaLink="true">https://jesustorres.es/monitoriza-tu-sistema-con-estilo-usando-conky</guid><category><![CDATA[Linux]]></category><category><![CDATA[monitoring]]></category><category><![CDATA[desktop]]></category><category><![CDATA[spanish]]></category><dc:creator><![CDATA[Jesús Torres]]></dc:creator><pubDate>Mon, 28 Sep 2015 11:00:49 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1638553649224/vOVdW6jcW.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>Encabeza este artículo el tema</em> <a target="_blank" href="https://www.gnome-look.org/p/1115403"><em>Conky Colors</em></a></p>
<hr />
<p>Ordenador recién instalado con Kubuntu 15.04, shell y terminal bien configurada, llega la hora de buscar una herramienta para monitorizar el sistema y estar, en lo posible, al tanto de cuando le estoy pidiendo demasiado. Hasta ahora esto lo hacía con un sencillo control de KDE 4 que no está disponible para KDE Plasma 5.2, aunque todo parece apuntar que estará de vuelta en la versión 5.3.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1635808393183/tE9gHI5gR.png" alt="Nuevos controles del monitor del sistema en KDE Plasma 5.3" class="image--center mx-auto" /></p>
<p>En todo caso, me enteré demasiado tarde de la noticia y algunos de los que la han probado tienen sus reservas sobre el consumo de CPU del nuevo <em>widget</em>. Por lo que he estado probado <a target="_blank" href="http://conky.sourceforge.net/">Conky</a>, un monitor del sistema capaz de mostrar toda la información que se quiera en el fondo del escritorio.</p>
<p>Como prueba de lo que se puede hacer con tiempo, buen gusto y un poco de habilidad, nada mejor que:</p>
<ul>
<li><p>Visitar esta lista de los <a target="_blank" href="http://devmadness.com/os-software/conky-themes-scripts-configs/">12 mejores temas para Conky</a>.</p>
</li>
<li><p><a target="_blank" href="http://www.deviantart.com/browse/all/?q=conky">Buscar Conky</a> en DevianArt.</p>
</li>
<li><p>Visitar el <a target="_blank" href="https://www.reddit.com/r/Conkyporn/">subreddit Conkyporn</a>.</p>
</li>
<li><p>Visitar la <a target="_blank" href="https://plus.google.com/u/0/communities/104794997718869399105/stream/c411c91a-2e51-4666-b3cc-13caf1c2dfc9">categoría Conky</a> de la comunidad Eye Candy Linux de Google+.</p>
</li>
</ul>
<p><a target="_blank" href="http://yesthisisme.deviantart.com/art/Conky-Conky-Conky-174343321"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1637191224532/IjrxJmurM.png" alt="Tema Conky, Conky, Conky de YesThisIsMe" class="image--center mx-auto" /></a></p>
<p>El único problema es que hacer estas verdaderas obras de arte no es tan sencillo.</p>
<p>Es el archivo de configuración de <a target="_blank" href="http://conky.sourceforge.net/">Conky</a> —por defecto <code>~/.conkyrc</code>— en el que se indica qué se debe mostrar y cómo. Todo en él son variables. Algunas dan acceso a estadísticas del sistema operativo —uso de la CPU, la memoria, el disco o la red, estadísticas de ejecución de los procesos en ejecución y <a target="_blank" href="http://linux.die.net/man/1/uptime">uptime</a>, entre otras variables—otras dan información sobre las cuentas de IMAP e POP configuradas o sobre el estado de la reproducción en alguno de los reproductores multimedia soportados—para por ejemplo conocer la canción que está sonando en MPD, XMMS2, BMPx o Audacious— y, por último, algunas facilitan cambiar la forma en la que se muestra esta información.</p>
<p>Por ejemplo, para mostrar en gris claro la cantidad de memoria usada respecto a la cantidad total:</p>
<pre><code class="lang-bash"><span class="hljs-variable">${color lightgrey}</span>RAM:<span class="hljs-variable">$color</span> <span class="hljs-variable">$mem</span>/<span class="hljs-variable">$memmax</span> - <span class="hljs-variable">$memperc</span>%
</code></pre>
<p>Aunque también podemos mostrar la misma información utilizando un gráfico de barras:</p>
<pre><code class="lang-bash"><span class="hljs-variable">${membar}</span>
</code></pre>
<p><a target="_blank" href="http://conky.sourceforge.net/">Conky</a> también permite ejecutar nuestros propios scripts y usar su salida como un valor, si encontramos con que hay alguna estadística del sistema operativo o del hardware que no soporte por defecto.</p>
<p>Sin embargo, muchos de los que hacen los fantásticos temas que he enlazado antes optan por una solución bastante más flexible. Utilizan <a target="_blank" href="https://es.wikipedia.org/wiki/Lua">Lua</a>, un lenguaje muy sencillo de empotrar en otros programas. <a target="_blank" href="https://es.wikipedia.org/wiki/Lua">Lua</a> nos permite obtener cualquier valor que nos interese y representarlo como nos venga en gana, ya que <a target="_blank" href="http://conky.sourceforge.net/">Conky</a> exporta hacia <a target="_blank" href="https://es.wikipedia.org/wiki/Lua">Lua</a> la API de Imlib2 y Cairo. Las mismas librerías que él usa para generar su salida gráfica en el escritorio.</p>
<p>Así que si queremos poner algo bonito en marcha lo más rápido posible, mejor optamos por alguno de los temas desarrollados por la comunidad.</p>
<h2 id="heading-puesta-en-marcha">Puesta en marcha</h2>
<p>Obviamente, lo primero es instalar <a target="_blank" href="http://conky.sourceforge.net/">Conky</a>. En Debian, Ubuntu y otras distribuciones derivadas existen dos paquetes:</p>
<pre><code class="lang-sh">conky-std
</code></pre>
<p>Es la versión que soporta las características más comunes.</p>
<pre><code class="lang-sh">conky-all
</code></pre>
<p>Es la versión que soporta todas las características —entre otras cosas incluye todo el soporte de <a target="_blank" href="https://es.wikipedia.org/wiki/Lua">Lua</a>— por lo que es la que recomiendan muchos desarrolladores de temas.</p>
<p>Por lo que si hacemos:</p>
<pre><code class="lang-sh">sudo apt-get install conky-all
conky
</code></pre>
<p>deberíamos ver como actualiza automáticamente nuestro fondo de escritorio.</p>
<p>Si observamos cierto parpadeo es porque debemos indicar a <a target="_blank" href="http://conky.sourceforge.net/">Conky</a> que utilice doble búfer. Esto se puede hacer ejecutando el programa con la opción <code>-b</code> o asegurándonos de que el archivo de configuración contiene la línea:</p>
<pre><code class="lang-bash">double_buffer yes
</code></pre>
<p>Como acabamos de instalar el programa está usando la configuración por defecto, pero eso no es problema porque podemos volcarla:</p>
<pre><code class="lang-sh">conky -C &gt; ~/.conkyrc
</code></pre>
<p>y añadir la línea sobre el doble búfer al archivo.</p>
<h2 id="heading-si-usas-plasma-5-y-se-ve-feo-de-espanto">Si usas Plasma 5 y se ve feo de espanto</h2>
<p>Si utilizas KDE lo más probable es que ahora mismo <a target="_blank" href="http://conky.sourceforge.net/">Conky</a> te parezca feo de narices. En tu caso el problema es que cualquiera que sea el tema que utilices debes comprobar que el archivo de configuración incluye las siguientes líneas:</p>
<pre><code class="lang-bash">own_window yes
own_window_type normal
own_window_argb_visual yes
own_window_argb_value 0
own_window_transparent yes
own_window_hints undecorated,below,sticky,skip_taskbar,skip_pager
</code></pre>
<p>Además, se supone que si <a target="_blank" href="http://conky.sourceforge.net/">Conky</a> está en ejecución cuando salgas de la sesión, volverá a ser iniciado automáticamente cuando vuelvas a entrar. Si eso no ocurre lo mejor es indicarle a KDE que siempre intente iniciarlo automáticamente.</p>
<pre><code class="lang-sh">ln -s /usr/bin/conky ~/.kde4/Autostart/conky
</code></pre>
<h2 id="heading-conky-manager">Conky Manager</h2>
<p>Cada tema tiene su propia forma de instalarse. Por ejemplo, en algunos casos tendremos que instalar paquetes adicionales, como <code>lm-sensors</code> o <code>hddtemp</code>. Así que mejor seguir en cada caso las instrucciones del desarrollador paso a paso.</p>
<p>Sin embargo, hay una manera más sencilla de hacer las cosas y es usando <a target="_blank" href="http://www.teejeetech.in/p/conky-manager.html">Conky Manager</a>. Este programa es una interfaz gráfica para configurar <a target="_blank" href="http://conky.sourceforge.net/">Conky</a> y los temas que más nos interesen. También se hace cargo de iniciar <a target="_blank" href="http://conky.sourceforge.net/">Conky</a> durante el arranque del sistema, por lo que no tendremos que preocuparnos de nada.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1635808396196/Q35BODrG5.png" alt="Ventana principal de Conky Manager." class="image--center mx-auto" /></p>
<p>Para utilizarlo primero instalamos el PPA del proyecto y después el programa propiamente dicho.</p>
<pre><code class="lang-sh">sudo apt-add-repository -y ppa:teejee2008/ppa
sudo apt-get update
sudo apt-get install conky-manager
</code></pre>
<p>Al ejecutarlo veremos un listado con todos los controles —o <em>widgets</em>— disponibles. Al seleccionar cualquier de ellos observaremos una previsualización en la parte inferior. Mientras que utilizando el icono del lápiz podemos configurar parámetros tales como la posición del control, el tamaño o el color de fondo.</p>
<p>Cuando lo tenemos claro marcamos en el <em>cuadro de verificación</em> de la izquierda aquellos controles que nos interesen. Así, cuando pulsemos el botón de <em>play</em>, <a target="_blank" href="http://conky.sourceforge.net/">Conky</a> se ejecutará mostrándolos tal y como los hemos configurado.</p>
<p><a target="_blank" href="http://www.teejeetech.in/p/conky-manager.html">Conky Manager</a> trae por defecto muy pocos temas, pero eso se puede arreglar fácilmente. Primero tenemos el <a target="_blank" href="http://www.mediafire.com/download/icvmpzhlk7vgejt/default-themes-extra-1.cmtp.7z">paquete de temas oficiales del proyecto</a> y además Jesse Avalos hace su propio <a target="_blank" href="http://www.mediafire.com/download/5yb5ambg6h4jack/Deluxe_Conky_Theme_Pack.cmtp.7z">Delux Conky Pack</a> que actualiza y anuncia regularmente en la comunidad <a target="_blank" href="https://plus.google.com/u/0/communities/104794997718869399105/stream/c411c91a-2e51-4666-b3cc-13caf1c2dfc9"><s>Eye Candy Linux de Google+</s></a>, de la que es el propietario. Para usarlos solo es necesario descargar estos paquetes e importarlos en <a target="_blank" href="http://www.teejeetech.in/p/conky-manager.html">Conky Manager</a> utilizando el botón correspondiente.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1635808397777/GaNmumTIG.png" alt="Importar temas en Conky Manager." class="image--center mx-auto" /></p>
<p>Ahora solo nos queda probar los nuevos controles y elegir los que más nos gusten. Y si no hay ninguno, echarle ganas y crear nuestro propio tema para <a target="_blank" href="http://conky.sourceforge.net/">Conky</a>.</p>
]]></content:encoded></item></channel></rss>