Friday, 15 September 2017

How to use Intel GPU for desktop display and dedicate Nvidia GPU for CUDA in Ubuntu?

[This solution has been rendered obsolete by the latest nvidia-415 driver, please see my Jan2019 post for the latest solution on this same problem]

Nowadays, most of modern desktop and laptop motherboards have a built-in Intel GPU for graphics display. In Ubuntu, if the desktop display uses Nvidia GPU (`prime-select nvidia`), then:
  1. when you are running CUDA simulations, you will often experience some lags or latency when manipulating with desktop items, e.g., switching to another desktop, maximizing/minimizing windows;
  2. you have less graphics memory for CUDA simulations since many desktop windows programs (including Windows itself) uses GPU memory for graphics acceleration.
The solution to this latency is to dedicate the Intel GPU for desktop display and dedicate the Nvidia GPU for CUDA programs. http://osdf.github.io/blog/intel-integrated-graphics-dedicated-gpu-for-cuda-and-ubuntu-1310.html has given a very sophisticated, complicated and long-winded but nonetheless working solution. We have a much simpler way of doing so.

Assuming you have correctly setup Nvidia driver and CUDA library, and you are able to run desktop and CUDA using your Nvidia GPU. Do the following two steps:
  1. prime-select intel
  2. append the following code in your .profile or .bashrc
if [ `ps aux | grep compiz | wc -l` -ge 2 ]; then
        nvpath=`echo /usr/lib/nvidia-???`
        export LD_LIBRARY_PATH=$nvpath:$LD_LIBRARY_PATH
fi
This will make all desktop 3D accelerations (desktop display programs like Xorg, compiz, and all OpenGL programs) to use Intel GPU, while all CUDA simulation programs (including nvidia-smi) will use Nvidia GPU. Of course, since the above code looks for the process named compiz to determine whether you are already inside desktop environment, thus, if you are not using Unity(3D) desktop, you need to change the process name correspondingly, otherwise, you might end up with a login loop and have to press Ctrl+Alt+F1 to switch to TTY to troubleshoot.

The principle is that in order to use GPU acceleration for CUDA programs (including nvidia-smi), your LD_LIBRARY_PATH must contain /usr/lib/nvidia-???

If later, you need to switch back to use Nvidia GPU for running desktop 3D programs like Blender, you can simply run `prime-select nvidia` and re-login.



The above solution works only on computers whose BIOS supports primary display device selection. Many CUDA-ignorant vendors such as Dell thought that whenever a dedicated GPU is plugged into PCIe, the on-board Intel GPU will never be used. Thus, their BIOS will automatically disable Intel GPU if a dedicated GPU is plugged into PCIe.

On such computers, you will see a black screen after doing the above steps. You have to forcefully set the PCI BusID of your desktop display device. To do so, first you need to obtain the PCI BusID of your Intel graphics card by running lspci:
00:02.0 Display controller: Intel Corporation Xeon E3-1200 v2/3rd Gen Core processor Graphics Controller (rev 09)
01:00.0 VGA compatible controller: NVIDIA Corporation GM206 [GeForce GTX 960] (rev a1)
Take note of the BusID of the Intel graphics card, i.e., 00:02.0. After that, you need to edit your /etc/X11/xorg.conf as below:
Section "Device"
        Identifier "intel"
        Driver "intel"
        BusID "PCI:0:2:0"
EndSection

Section "Screen"
        Identifier      "intel"
        Device          "intel"
EndSection
By doing so, you force your display device to use Intel driver on Intel GPU's PCI BusID.

Now, you can see your screen and enter desktop. But you will find out that you cannot run any CUDA program even with LD_LIBRARY_PATH=/usr/lib/nvidia-###. The reason is because Nvidia driver is loaded but never connected. You must first run the following as root once:
LD_LIBRARY_PATH=/usr/lib/nvidia-### nvidia-smi
After that, everything will work as usual. You can put the above line in your /etc/rc.local to make it auto-run every time the machine reboots.

One drawback of such a configuration is that you will not be able to see your screen before reaching the login screen unless you plug your monitor cable into Nvidia card; moreover, once you have reached the login screen, you won't be able to see TTY by pressing Ctrl+Alt+F1, regardless of whether you plug monitor into motherboard or Nvidia card.
The other drawback of this is that you cannot run from command line any GUI program that uses hardware acceleration, e.g., SDL2, OpenGL, etc. This is because your desktop is using Intel GPU, thus, any desktop GUI program that uses hardware acceleration must also use Intel GPU. So the solution is to remove /usr/lib/nvidia-### from LD_LIBRARY_PATH when running those hardware accelerated GUI programs.

Tuesday, 1 August 2017

How to port Linux executables from one system onto another?

There are many Linux distributions, e.g., Ubuntu, Redhat, CentOS, Debian, etc. Even for the same distribution, there are many versions. We often want to port a compiled executable from one system directly onto another system without re-compiling, because compilation is very tedious and time consuming.

Firstly, we need to collect all dependent dynamic libraries, use the following command:


 ldd -v <executable>

Secondly, copy your target executable (we call it <exec>) together with all dependency libraries (those *.so files after "=>") into a folder (we call it <exec-lib>), and then copy the folder onto another machine.

Lastly, you can run your target executable on the new system in the following way. Out of all your copied libraries, there is one called ld-linux*.so.* (we call it ld.so). This is the main library loader, it is used in the following way:
 ld.so --library-path <exec-lib>  <exec>

In this way, you can get rid of the notorious "GLIBC_XXX not found" error. However, if you encounter the error "FATAL: kernel too old", that means your program has used certain new features in the newer system, and then you do have to re-compile in a system with old-version kernel.

Thursday, 28 July 2016

How to install tensorflow on ancient cluster machines without root?

I have eventually managed to install Tensorflow on our school's server cluster. Server machines have Python 2.6.6, no pip, gcc 4.4, GLIBC 2.12. I have no root access.

Installing Python 2.7.6 and pip as user should not be a problem.

For Tensorflow, firstly:
pip install --user --upgrade https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.9.0-cp27-none-linux_x86_64.whl
or (for GPU)
pip install --user --upgrade https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow-0.9.0-cp27-none-linux_x86_64.whl 
(I installed the CPU-only version as there is no GPU; the GPU version is installed in the same way on my colleague's GPU cluster)

Now, when you import tensorflow in Python, you will encounter the notorious GLIBC-version-not-found error:
ImportError: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.17' not found (required by /usr/local/lib/python2.7/dist-packages/tensorflow/python/_pywrap_tensorflow.so)

To proceed, firstly download and extract glibc 2.17:
cd ~ 

wget http://launchpadlibrarian.net/137699828/libc6_2.17-0ubuntu5_amd64.deb 

wget http://launchpadlibrarian.net/137699829/libc6-dev_2.17-0ubuntu5_amd64.deb 

wget ftp://rpmfind.net/linux/sourceforge/m/ma/magicspecs/apt/3.0/x86_64/RPMS.lib/libstdc++-4.8.2-7mgc30.x86_64.rpm

ar p libc6_2.17-0ubuntu5_amd64.deb data.tar.gz | tar zx

ar p libc6-dev_2.17-0ubuntu5_amd64.deb data.tar.gz | tar zx

rpm2cpio libstdc++-4.8.2-7mgc30.x86_64.rpm | cpio -idmv

Then, create an executable shell script named python, e.g., at $HOME/bin/python and put in the following line:
$HOME/lib/x86_64-linux-gnu/ld-2.17.so --library-path "$HOME/lib/x86_64-linux-gnu:$LD_LIBRARY_PATH:$HOME/usr/lib64/" $HOME/.local/bin/python $*
where $HOME/.local/bin/python is the correct version of Python, which should usually be in /usr/bin/python, (in my case, since I have installed Python 2.7.6 as user to over-ride the system's Python 2.6.6, my own Python 2.7.6 is put in $HOME/.local/bin/python)

Add related paths into your $HOME/.profile, make sure in your $PATH, $HOME/bin is before that of the correct version of Python:
export LD_LIBRARY_PATH="$HOME/lib:$HOME/.local/lib:$LD_LIBRARY_PATH"
export LIBRARY_PATH="$HOME/lib:$HOME/.local/lib:$LIBRARY_PATH"
export CPLUS_INCLUDE_PATH="$HOME/include:$CPLUS_INCLUDE_PATH"
export C_INCLUDE_PATH="$HOME/include:$C_INCLUDE_PATH"

export PATH="$HOME/bin:$HOME/.local/bin:$PATH"

Now, you should be able to run your Tensorflow script using the python:
python your-tensorflow-code.py

Take note, if you used to put #!/usr/bin/python as the first line in your script and type ./your-tensorflow-code.py to run, you need to change that as well, or just explicitly type "python ./your-tensorflow-code.py".

QED

Friday, 1 May 2015

Install Office2010 in Wine1.7 on Ubuntu 14.04

At May 2015, since newer versions of Ubuntu and Wine does not install winbind and samba by default, using the old method for installing Office2010 will cause an error:
err:msi:ITERATE_Actions Execution halted, action L"CAInstallSppPlugin.x86" returned 1603

and fail halfway with "Microsoft Office has encountered an error during setup" and the installation will abort.

Here are the steps:
1. install wine1.7 via ppa (root)
add-apt-repository ppa:ubuntu-wine/ppa
apt-get update
apt-get install wine1.7

2. install OpenGL packages
apt-get install mesa-utils mesa-utils-extra libgl1-mesa-glx:i386 libgl1-mesa-dev lib32z1

3. link OpenGL packages
ln -s /usr/lib/i386-linux-gnu/mesa/libGL.so.1 /usr/lib/i386-linux-gnu/mesa/libGL.so
ln -s /usr/lib/i386-linux-gnu/mesa/libGL.so /usr/lib/i386-linux-gnu/libGL.so

4. install samba and winbind
apt-get install samba winbind

5. create 32-bit wine prefix
export WINEARCH=win32
export WINEPREFIX=$HOME/.wine32
(you can name .wine32 to anything you like, but subsequent things you do will only apply to that prefix folder)


6. (Optional) install winetrick dll components
winetricks vcrun2008 dotnet20 dotnet40 msxml6
winetricks riched20 riched30 gdiplus vb6run ie8 corefonts

7. run winecfg
make sure it is Windows XP, with riched20 and gdiplus set to native(windows)

8. Run office2010 setup
wine office2010-setup/setup.exe

9. Edit registry
If you encounter a window pop out saying "Please wait while windows configures Microsoft Office Professional Plus 2010" everytime you open Word2010, run registry editor to add the following variable:
reg add HKCU\Software\Microsoft\Office\14.0\Word\Options /v NoReReg /t REG_DWORD /d 1

10. Set environment to type Chinese in Office,
LC_ALL=zh_CN.UTF-8 wine .wine32/drive_c/Program\ Files/Microsoft\ Office/Office14/WINWORD.EXE

Monday, 30 March 2015

Installing conflicting packages on Ubuntu

Currently, Wine and CUDA cannot be both installed due to a conflict between ocl-icd-libopencl1 and nvidia-opencl-icd-340, because they both contain the files /usr/lib/x86_64-linux-gnu/libOpenCl.so.1.0.0 and /usr/lib/i386-linux-gnu/libOpenCL.so.1.0.0 as well as symlinks for those files.


Method 1:
One way to solve this problem is to cheat the Ubuntu package manager that CUDA is not installed but if fact it is installed.
The steps are as follows:
  1. a. get the package list: dpkg --get-selections > anyfile
    b. edit anyfile to set nvidia-opencl-icd-340 as deinstalled, save the file
    c. set the package list: dpkg --set-selections < anyfile
  2. edit the corresponding file /var/lib/dpkg/status, for every package you want to set to deinstalled, delete the entire entry, save the file.
  3. Resolve conflicts apt-get clean aptitude
Repeat Steps 1-3 for every conflicts you encounter, set those packages to deinstalled.
  1. Install wine using apt-get or aptitude
In this way, you will have both Wine and CUDA physically installed (and you can run both correctly), but the package manager will only see that Wine is installed. As a result, you won't be able to directly install subsequent packages like python-pycuda which depends on CUDA. You can either install them from source or download the .deb file and use dpkg to force install them ignoring dependency, and then repeat Steps 1 and 2 to set them as deinstalled.


Method 2 (better):
Once you understand how this mechanism works. Now you can make the whole process easier by directly modifying the Conflict/Depends/Provides entries of related packages in /var/lib/dpkg/status before running apt-get install, so that the conflicts no longer exist in the first place when you run apt-get install.
For INSTALLED packages, you can modify the dependency settings in /var/lib/dpkg/status so that they will no longer cause any conflict with new packages to be installed.
For not-yet-installed packages, you can modify their dependencies in /var/lib/apt/lists/*_Packages, so that they can be installed without conflicting with existing packages.
Since the dependency information is also present in the *.deb package files, direct installation using apt-get/aptitude will fail, you need to install them forcefully, i.e.,
dpkg --force-all -i *.deb

The second method is more powerful because the package manager will now see both Wine and CUDA installed. Thus, you can use apt-get to install subsequent packages which depends on Wine and CUDA without incurring any conflict or unmet dependencies. Moreover, changing or updating repositories (apt-get update) will not cause the conflict to re-occur.

Monday, 8 September 2014

Linux C++ : create a process and bind its stdin, stdout and stderr to C++ I/O streams

The following function creates a new process from command line and bind its stdin, stdout and stderr to C++ I/O streams.
It's more preferable to use Boost to do so since Boost is cross-platform. In fact, the code is simpler if you use Boost


// C code
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vector>
#include <iostream>
#include <fstream>
#include <sstream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <ext/stdio_filebuf.h>


int spawn(const char *cmd, int io_mask, ostream **stdin, istream **stdout, istream **stderr){
    // io_mask: bit0:stdin, bit1:stdout, bit2:stderr
    int pipes[3][2];
    for(int x=0; x<3; ++x)
        pipe(pipes[x]);
    int pid;
    if((pid=fork())!=0){    // parent
        if(io_mask&1){    // create stdin
            __gnu_cxx::stdio_filebuf<char> *filebuf = new __gnu_cxx::stdio_filebuf<char>(pipes[0][1], std::ios::out);
            *stdin = new ostream(filebuf);
        }
        if(io_mask&2){    // create stdout
            __gnu_cxx::stdio_filebuf<char> *filebuf = new __gnu_cxx::stdio_filebuf<char>(pipes[1][0], std::ios::in);
            *stdout = new istream(filebuf);
        }
        if(io_mask&4){    // create stderr
            __gnu_cxx::stdio_filebuf<char> *filebuf = new __gnu_cxx::stdio_filebuf<char>(pipes[2][0], std::ios::in);
            *stderr = new istream(filebuf);
        }
        return pid;
    } else {            // child
        if(io_mask&1)
            dup2(pipes[0][0], STDIN_FILENO);
        if(io_mask&2)
            dup2(pipes[1][1], STDOUT_FILENO);
        if(io_mask&4)
            dup2(pipes[2][1], STDERR_FILENO);
        int retval;
        do{
            cerr << "Creating process with command-line \"" << cmd << "\"" << endl;
            retval = system(cmd);
            cerr << "Decoder thread has exited with code " << retval << endl;
        }while(io_mask&0x80000000);
        _exit(retval);
    }
}





// C++ code
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <map>
#include <set>
#include <boost/thread.hpp>

using namespace std;


class Thread{
public:
int m_pipes[3][2]; // for stdin, stdout and stderr respectively
int m_mask; // mask: bit0:stdin, bit1:stdout, bit2:stderr, bit31:persistent launch
string m_cmdline;
ostream *m_stdin;
istream *m_stdout;
istream *m_stderr;
boost::thread *m_thread;
__gnu_cxx::stdio_filebuf<char> *m_filebuf[3]; // for stdin, stdout and stderr respectively

static void _thread_func(Thread *p){ // OOP connector
p->thread_func();
}

template <class A>
ostream& operator << (A &a){
return (*m_stdin) << a;
}

template <class A>
istream& operator >> (A &a){
return (*m_stdout) >> a;
}

void flush(){
m_stdin->flush();
}

istream& getline(string &line){
return std::getline(*m_stdout, line);
}

ostream& putline(string &line){
ostream& ret = (*m_stdin << line << endl);
m_stdin->flush();
return ret;
}

void thread_func(){
// child thread
if(m_mask&1)
dup2(m_pipes[0][0], STDIN_FILENO);
if(m_mask&2)
dup2(m_pipes[1][1], STDOUT_FILENO);
if(m_mask&4)
dup2(m_pipes[2][1], STDERR_FILENO);
int retval;
do{
cerr << "Creating process with command-line \"" << m_cmdline << "\"" << endl;
retval = system(m_cmdline.c_str());
cerr << "Decoder thread has exited with code " << retval << endl;
}while(m_mask&0x80000000);
_exit(retval);
}

Thread(const string &cmdline, int mask=7):m_cmdline(cmdline),m_mask(mask){
for(int x=0; x<3; ++x)
pipe(m_pipes[x]);
m_thread = new boost::thread(&_thread_func, this);

// parent thread
if(m_mask&1){ // bind stdin
m_filebuf[0] = new __gnu_cxx::stdio_filebuf<char>(m_pipes[0][1], std::ios::out);
m_stdin = new ostream(m_filebuf[0]);
}
if(m_mask&2){ // bind stdout
m_filebuf[1] = new __gnu_cxx::stdio_filebuf<char>(m_pipes[1][0], std::ios::in);
m_stdout = new istream(m_filebuf[1]);
}
if(m_mask&4){ // bind stderr
m_filebuf[2] = new __gnu_cxx::stdio_filebuf<char>(m_pipes[2][0], std::ios::in);
m_stderr = new istream(m_filebuf[2]);
}
}

~Thread(){
for(int x=0; x<3; ++x)
close(m_pipes[x][0]), close(m_pipes[x][1]);
delete m_thread;
}

};

Wednesday, 12 February 2014

Python multi-threading/multi-processing

Python multi-threading does not actually run on multiple CPUs due to Global Interpreter Lock, so it is useless. We can only use python multi-processing, which also has some bugs.

# 1. include package
from multiprocessing import Process, Manager

# 2. only variables created using manager can be shared across difference processes
manager=Manager()
arr=manager.list()

# 3. create process
p=Process(target=filterRuleTable, args=(arr, i, inputSentences, N, options,))

# 4. start running
p.start()

# 5. wait for termination
p.join()