четверг, 8 сентября 2011 г.

Настройка PuTTY для доступа к удаленной машине по SSH


Скачиваем PuTTY, Pageant и PuTTYgen:

Генерировать OpenSSH-ключи мне не нужно, я их получил в процессе настройки mercurial-server-а на Ubuntu, после чего просто скопировал их в Windows.

PuTTY использует иной формат ключей в отличие от OpenSSH, поэтому нам необходимо конвертировать наш приватный ключ в формат PuTTY. Для этого мы воспользуемся PuTTYgen:

1. Conversions >> Import key
2. Save private key

В результате получим файл ключом, который можно использовать с PuTTY и Pagent.

Настраиваем PuTTY:

1. Session >> Вводим hostname или ip-адрес сервера и выбираем SSH протокол.
2. Connections >> Data >> Вводим имя для авто-логина в систему.
3. Connections >> SSH >> Auth >> Private key file for autherization >> Browse >> Выбираем файлик с ключом.
4. Можно сохранить текущую конфигурацию PuTTY в реестр, для этого на вкладке Session есть кнопка Save.
5. Всё, можно кликать Open.

Чтобы получить доступ к ssh из других приложений, необходимо запустить Pagent и выбрать файл с ключиком, который получили от  PuTTYgen.

Ну и собственно ради чего это все затевалось:

C:\Users\Мишка>hg clone ssh://hg@192.168.1.2/lightpack
destination directory: lightpack
requesting all changes
adding changesets
adding manifests
adding file changes
added 620 changesets with 2562 changes to 634 files (+4 heads)
updating to branch default
329 files updated, 0 files merged, 0 files removed, 0 files unresolved

C:\Users\Мишка>

Ubuntu Mercurial Server


brunql@brunql-desktop:~$ sudo apt-get install mercurial-server 
[sudo] password for brunql: 
...
Настраивается пакет mercurial-server (1.0.1-1) ...
brunql@brunql-desktop:~$ ssh-keygen -C brunql@gmail.com
Generating public/private rsa key pair.
Enter file in which to save the key (/home/brunql/.ssh/id_rsa): 
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/brunql/.ssh/id_rsa.
Your public key has been saved in /home/brunql/.ssh/id_rsa.pub.
The key fingerprint is:
97:c6:1d:95:f1:d4:09:61:d8:2d:90:6a:ab:2f:9e:b6 brunql@gmail.com
The key's randomart image is:
+--[ RSA 2048]----+
|           .=+*o+|
|           o.+.=.|
|          . . . .|
|         + o .   |
|        S * .    |
|         +       |
|        .        |
|       +.        |
|      oE+.       |
+-----------------+
brunql@brunql-desktop:~$ ssh-agent 
SSH_AUTH_SOCK=/tmp/ssh-KMcMgw3965/agent.3965; export SSH_AUTH_SOCK;
SSH_AGENT_PID=3966; export SSH_AGENT_PID;
echo Agent pid 3966;
brunql@brunql-desktop:~$ ssh-add
Enter passphrase for /home/brunql/.ssh/id_rsa: 
Identity added: /home/brunql/.ssh/id_rsa (/home/brunql/.ssh/id_rsa)
brunql@brunql-desktop:~$ ssh-add -L > my-key
brunql@brunql-desktop:~$ sudo cp my-key /etc/mercurial-server/keys/root/brunql
brunql@brunql-desktop:~$ sudo -u hg /usr/share/mercurial-server/refresh-auth 
brunql@brunql-desktop:~$ 
brunql@brunql-desktop:~$ hg init ssh://hg@192.168.1.2/lightpack
The authenticity of host '192.168.1.2 (192.168.1.2)' can't be established.
RSA key fingerprint is 14:df:e8:92:af:3a:56:1f:9a:20:1b:fa:fa:a3:da:05.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.1.2' (RSA) to the list of known hosts.
brunql@brunql-desktop:~/code/lightpack-old$ hg push ssh://hg@192.168.1.2/lightpack
pushing to ssh://hg@192.168.1.2/lightpack
searching for changes
remote: adding changesets
remote: adding manifests
remote: adding file changes
remote: added 619 changesets with 2561 changes to 633 files (+8 heads)
brunql@brunql-desktop:~/code/lightpack-old$ ls /var/lib/mercurial-server/repos/
hgadmin  lightpack
brunql@brunql-desktop:~/code$ hg clone ssh://hg@192.168.1.2/lightpack
destination directory: lightpack
requesting all changes
adding changesets
adding manifests
adding file changes
added 619 changesets with 2561 changes to 633 files (+8 heads)
updating to branch default
329 files updated, 0 files merged, 0 files removed, 0 files unresolved
brunql@brunql-desktop:~/code$ 


http://ekkescorner.wordpress.com/blog-series/git-mercurial/step-by-step-install-mercurial-server-on-ubuntu/
http://dev.lshift.net/paul/mercurial-server/docbook.html
http://matttrent.com/articles/how-use-ssh-agent-windows-tortoisesvn

понедельник, 5 сентября 2011 г.

Linux command-line interface

sudo lshw
sudo lshw -html > hw.html
sudo lspci
cat /proc/cpuinfo
cat /proc/meminfo
sysinfo
sudo dmidcode

$ file 'libinkview.so'
libinkview.so: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, stripped


$ readelf -h /bin/bash
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x41f210
  Start of program headers:          64 (bytes into file)
  Start of section headers:          932480 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         9
  Size of section headers:           64 (bytes)
  Number of section headers:         29
  Section header string table index: 28


$ gcc -m32

воскресенье, 19 июня 2011 г.

Великая битва OpenMP vs MPI (или Холодное vs Красное)

Считаем интеграл методом левых прямоугольников. Просто и безвкусно.


Вычисления будем проводить на одной машине, потому что у меня их одна.

Главное действующее лицо: Intel(R) Pentium(R) Dual CPU E2200 @ 2.20GHz
OS: Ubuntu 10.04 2.6.32-32-generic x86_64
MPICH2 Version: 1.2.1p1
GCC: 4.4.3-4ubuntu5

OpenMP вариант численного интегрирования:

/*
 *         DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
 *                    Version 2, December 2004
 *
 * Copyright (C) 2011 Brunql
 *
 * Everyone is permitted to copy and distribute verbatim or modified
 * copies of this license document, and changing it is allowed as long
 * as the name is changed.
 *
 *            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
 *   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
 *
 *  0. You just DO WHAT THE FUCK YOU WANT TO.
 */
#include <omp.h>
#include <stdio.h>
#include <cmath>
#include <string>

// Integral limits [a;b)
const double a = 0;
const double b = M_PI;
// Number of quantization steps in [a,b)
const int N = (500*1000*1000);

// Quantization step
const double step = (b - a) / N;

// Integral evaluation function
static inline double f(double x)
{
    return cos(x)*sin(x)*x*x + 2;
}

double evalIntegral()
{
    double result = 0;
#   pragma omp parallel for reduction(+:result) schedule(dynamic,(N/1000))
    for(int i = 0; i < N; i++)
    {
        double x = a + i * step;
        result += f(x) * step;
    }
    return result;
}

int main(int argc, char **argv)
{
    printf("=> OpenMP\n");
    printf("Number of quantization steps %iM\n", N / 1000000);
    fflush(stdout);
#   pragma omp parallel
    {
#       pragma omp critical
        {
            printf("Start working thread #%i of %i\n",
                   omp_get_thread_num(), omp_get_num_threads());
        }
    }
    // Looooooong call
    double result = evalIntegral();

    printf("Result with OpenMP: %lf\n", result);
    return 0;
}

MPI вариант численного интегрирования:

/*
 *         DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
 *                    Version 2, December 2004
 *
 * Copyright (C) 2011 Brunql
 *
 * Everyone is permitted to copy and distribute verbatim or modified
 * copies of this license document, and changing it is allowed as long
 * as the name is changed.
 *
 *            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
 *   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
 *
 *  0. You just DO WHAT THE FUCK YOU WANT TO.
 */

#include <mpi.h>
#include <stdio.h>
#include <math.h>
#include <string.h>

// Integral limits [a;b)
const double a = 0;
const double b = M_PI;
// Number of quantization steps in [a,b)
const int N = (500*1000*1000);

// Quantization step
const double step = (b - a) / N;

// Integral evaluation function
static inline double f(double x)
{
    return cos(x)*sin(x)*x*x + 2;
}

double evalIntegral(int start, int end)
{
    double result = 0;
    for (int i = start; i < end; i++)
    {
        double x = a + i * step;
        result += f(x) * step;
    }
    return result;
}

int main (int argc, char* argv[])
{
    MPI_Init(&argc, &argv);

    int rank;
    int sizeOfWorld;
    MPI_Status mpiStatus;

    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &sizeOfWorld);

    static const int MasterRank = 0;

    if (rank == MasterRank)
    {
        // Master
        printf("=> MPI\n");
        printf("Number of quantization steps %iM\n", N / 1000000);
        fflush(stdout);
    }

    printf("Start working\n");
    fflush(stdout);

    int numOfWorkers = sizeOfWorld;
    int start = N / numOfWorkers * rank;
    int end = start + N / numOfWorkers;

    // Looooooong call
    double result = evalIntegral(start, end);

    printf("Job is done! [%i; %i) Result = %lf\n", start, end, result);
    fflush(stdout);

    if (rank != MasterRank)
    {
        // Workers send results to master
        MPI_Send(&result, 1, MPI_DOUBLE, MasterRank, 0, MPI_COMM_WORLD);
    }

    // Master collect results
    if (rank == MasterRank)
    {
        double resultFromWorker = 0;
        for (int id = 1; id < sizeOfWorld; id++)
        {
            MPI_Recv(&resultFromWorker, 1, MPI_DOUBLE, id,
                     MPI_ANY_TAG, MPI_COMM_WORLD, &mpiStatus);
            result += resultFromWorker;
        }
        printf("Result with MPI: %lf\n", result);
    }

    MPI_Finalize();
    return 0;
}

Барабанная дробь!


$ time ./openmp
=> OpenMP 
Number of quantization steps 500M 
Start working thread #0 of 2 
Start working thread #1 of 2 
Result with OpenMP: 3.815784
 
real 0m17.042s 
user 0m33.700s 
sys 0m0.020s

$ time mpirun -l -n 2 ./mpiapp 
0: => MPI 
1: Start working 
0: Number of quantization steps 500M 
0: Start working 
1: Job is done! [250000000; 500000000) Result = 0.307341 
0: Job is done! [0; 250000000) Result = 3.508443 
0: Result with MPI: 3.815784 

real 0m17.342s 
user 0m0.090s 
sys 0m0.030s


Представленные результаты являются моментальными, то есть никаких усреднений не проводилось. Делать какие-то выводы считаю бессмысленным в виду того, что сравнивать холодное с красным как минимум не логично. Использование MPI на одной машине с одним процессором и парой ядер практически бессмысленно. Единственная вещь, которая оправдывает затраченные усилия, это полученный опыт использования данных инструментов. Что собственно и являлось главной целью данного теста.

Пока писал примеры для сравнения производительности, у меня закралась шальная мысль, а что если их объединить? Смысла судя по тестам скорости не много, но ведь скорость работы это одно, а скорость разработки немного ортогональная вещь, которая очень сильно зависит от используемого инструмента. На OpenMP очень удобно постепенно распараллеливать уже написанный код, и ничуть не менее удобно писать новый. В тоже время MPI обеспечивает достаточно мощный интерфейс для обмена результатами вычислений между различными вычислительными блоками. Конечно на вскидку сложно придумать сферу применения данного подхода.


В общем будем считать, что победила дружба.