読者です 読者をやめる 読者になる 読者になる

手続き型音楽の日常

関数型音楽に乗り換えたい

Ubuntuのtaskselを使って、ラクしてKVM環境を作る

Linuxで楽しよう。Linuxを楽しもう。(名言っぽく言ってみるだけ)

ふと taskselxubuntu desktopを選ぼうとすると、そこにそれらしき項目があったので、使ってみた。その時のメモ。

基本、シェルはbashでroot権限で行きます。 sudo はつけないので、 su したくない方は sudo をつけて実行してください。

PCが仮想化に対応しているか確認する

KVMは完全仮想化をCPUの仮想化技術で実現しているようなので、次のコマンドで確認する。

# egrep -c '(vmx|svm)' /proc/cpuinfo

出力が1以上なら仮想化できます。

パッケージをインストールする

とりあえずKVM環境を動かすためのライブラリ群を入れます。次のコマンドを打ちます。

# tasksel

GUIっぽい画面が出てくるので、一覧から「Virtual Machine Host」に スペースキー でチェックを入れ、 エンターキー で続行します。

あとは待つだけ。これが終わると、仮想化に必要なものがほとんど入ります。

ただし、GUIで設定できる「virt-manager」はあいにく入れてくれないので、これだけは手動で入れます。

# apt install virt-manager

これがあれば、Virtual BoxみたいにGUIで簡単に操作ができるようになります。

ネットワークインターフェイス(NIC)をブリッジする

なんか、皆さんこぞってブリッジしているので、ブリッジしたほうが幸せなのかな?と半信半疑でブリッジしました。

一応パッケージをチェック。

# apt list | grep bridge-utils

[インストール済み] と末尾に表示されていなければ、インストールします。

# apt install bridge-utils

次に、ブリッジするよう /etc/network/interfaces を編集

Ubuntuは最近、規定のNICインターフェイス名が環境によって変わるようになったので、適宜読み替えてください。

auto enp0sXXXX
iface enp0sXXXX inet manual

auto br0
iface br0 inet static
address 192.168.XXX.XXX
network 192.168.XXX.0
netmask 255.255.255.0
gateway 192.168.XXX.XXX
dns-nameservers XXX.XXX.XXX.XXX
bridge-ports enp0sXXXX
bridge-stp off

元あった規定NICインターフェイスの設定はすべてコメントアウトか削除かしておきます。その設定を、br0側にすべて書きます。

この後、再起動して ifconfig でbr0側にIPアドレスなどが定義されていることを確認。

参考サイト

qiita.com

www.agilegroup.co.jp

Ubuntu 16.04 KVMのインストールと、bridge接続の構成 - Symfoware

aptでインストールした残骸を確認する

完璧に備忘録ですが。

パッケージの一覧を取得する

# apt list

パッケージの一覧が表示されます。インストール済みかそうでないかにかかわらず、データベースに登録してあるパッケージはすべて出ます。

たぶんこの一覧の中からパッケージの情報を取り出すんだと思います。

設定が残る

上記のコマンドで表示した一覧で、末尾に次のような表示がされることがあります。

  • [インストール済み]
  • [インストール済み、自動]
    • ほかのパッケージが依存しているか何かで、ユーザが直接指定していないけどインストールされたもの
  • [設定が残存]
    • アンインストールして、設定が残っている(再インストール時に既存の設定が使用される)

この「設定が残存」があると、再インストール時に --update フラグとかが自動でつけられたりして、クリーンインストールはしないようです。

設定を消す

# apt purge <パッケージ名>
# apt remove --purge <パッケージ名>

どちらでもいいみたい、

Ubuntu16.10でIPを固定しDNSを指定するのに、2時間かけました。

Ubuntuのことをあまり知らずに挑むからダメなんですよね。

とはいえ、IPを固定するくらいはいくらシステムの根幹に近いカスタマイズとはいえ、もうちょっと簡単でもいいと思うんですよ…

変更した箇所

  • /etc/network/interfaces
  • /etc/hosts
  • /etc/NetworkManager/NetworkManager.conf
  • /etc/resolvconf/resolv.conf.d/tail

いちおうこれらは確実に変更してあります。

ほかにも触ったところあったかもしれないけど、毎回Ubuntuマシン触るときに悩まされる種でもありイライラしていたので覚えていない…。これだからブログ向いてないんですよね。知ってます。

※なお、これから同じような設定をされる方は、ほかの方の記事やしっかりとした情報を一通り見てから実際に設定されることを強くお勧めします。

/etc/network/interfaces

auto lo
ifacw lo inet static

が初期設定。これを次のように変更します。

auto enpX
iface enpX inet static
    address <固定するアドレス XXX.XXX.XXX.XXX>
    netmask <サブネットマスク XXX.XXX.XXX.XXX>
    gateway <デフォルトゲートウェイ XXX.XXX.XXX.XXX>
    dns-nameservers <DNSサーバ XXX.XXX.XXX.XXX>

enpXNICのアドレスのようなもので、 ifconfig コマンドで確認ができます。

lo から enpX に変更するので、 ifconfig を走らせたときに lo と同じような位置に出てくるやつがそれです。

なおDNSサーバプライマリとセカンダリをスペースで区切って指定できるようです。

/etc/hosts

変更する意味があるかと言われれば、もしかしたらないかもしれないですが、一応変更します。

127.0.0.1 localhost
127.0.1.1 <コンピュータ名>

# The following lines are disirable for IPv6 capable hosts
::1     ip6-localhost ip6-loopback
・
・
・

最後のほうは面倒なので端折りました。

ここに出てくる 127.0.1.1 を変更します。

127.0.0.1 localhost
<固定するアドレス> <コンピュータ名>

# The following lines are disirable for IPv6 capable hosts
::1     ip6-localhost ip6-loopback
・
・
・

/etc/NetworkManager/NetworkManager.conf

悪党を倒しに行きます(?)

[main]
plugins=ifupdown,keyfile,ofono
dns=dnsmasq

[ifupdown]
managed=false

これを、以下のように直します。

[main]
plugins=ifupdown,keyfile,ofono
#dns=dnsmasq

[ifupdown]
managed=false

これで悪党は目覚めないことでしょう。きっと。

/etc/resolvconf/resolv.conf.d/tail

最後に強制的にDNSを変えます。もう最終手段です。

このファイルは、私の環境では入っていなかったため、自分で作りました。

そして以下のように記述します。

nameserver <DNSサーバ XXX.XXX.XXX.XXX (プライマリ)>
nameserver <DNSサーバ XXX.XXX.XXX.XXX (セカンダリ)>

果たして /etc/network/interfaces に記述した dns-nameservers に意味はあったのだろうか。

そして最後、 resolv.conf を生成します。

$ sudo resolvconf -u

再起動

最後に再起動すれば、IPアドレスは固定になり、DNSサーバも変わっているはず。

時間がかかった。

結局、表題の通りすべての帳尻合わせするため 2時間 以上はかけました。はい。

IPアドレスを固定するために /etc/interfaces を書き換えている方がたくさんいたのですが、それだけだとなぜかうまくいかなくて。

試行錯誤を重ねてやっと固定された感じです。つらい。

やっぱりここらへんはCentOSのほうが楽なんでしょうかね。。。

StringBuilderをstringと同じだけ作ると、どれほど遅いのか。

この間、以下のようなコードを見かけました。

StringBuilder strSql = new StringBuilder();
strSql.Append(@"SELECT * FROM ...
                WHERE ..."); // SQLは長いので省略。
this.ExecuteNonQuery(strSql.ToString());

フォームのメソッドに書かれていたのですが、フォーム自体がユーザコントロールになっていて、データベース接続の機能をすでに実装しているんですね。

なので、それにSQLを投げれば完了というすごくシンプルなものなのですが。

StringBuilderにする必要あったのかなって。

StringBuilderを必要とする理由

StringBuilder は、 string 型が演算で毎回新しいインスタンスを生成したり破棄したりするのに対して、最初のインスタンスを使いまわすために使う、というものだと思います。

具体的には次のコード。

string s = "";
s = s + "a";
s = s + "b";
s = s + "c";

上記のコードでは、最終的に変数 s に入るのは "abc" という文字列ですが、その文字列を得るまでにインスタンスを生成する回数は7回です。

それに対し、

StringBuilder s = new StringBuilder();
s.Append("a");
s.Append("b");
s.Append("c");

上記のコードでも同様に、最終的に変数 s に入るのは "abc" という文字列ですが、インスタンスの生成は4回で済みます。

インスタンスの生成、という観点からみると、 string 型より StringBuilder 型のほうが同じインスタンスを使いまわすためオーバーヘッドが少ないと考えられます。

しかし。

最初のコードって、はじめに StringBuilder 型の変数を確保しているので、毎回インスタンスを生成していることになるんですよね。

これではstring型を直で触るのと変わらないのでは…。

ということで調べてみました。

検証コード

次の検証コードを用意しました。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        /// <summary> 出力用ダミー変数 </summary>
        static string d_out;

        /// <summary>
        /// メインエントリポイント
        /// </summary>
        static void Main(string[] args)
        {
            try
            {
                int count1;
                int count2;
                List<double> measuredList = new List<double>();

                //------------------------------//
                // 入力
                //------------------------------//

                do
                    Console.WriteLine("1回の計測で確保を行う回数を指定してください...");
                while (!int.TryParse(Console.ReadLine(), out count1));

                do
                    Console.WriteLine("計測を行う回数を指定してください...");
                while (!int.TryParse(Console.ReadLine(), out count2));

                //------------------------------//
                // 計測 string
                //------------------------------//

                measuredList.Clear();
                Console.WriteLine("-------------------------------------------------------");
                Console.WriteLine("stringクラスで計測します。");

                GC.Collect(GC.MaxGeneration);
                for (int i = 0; i < count2; i++)
                {
                    measuredList.Add(MeasureTime_String(count1));
                    Console.WriteLine((i + 1).ToString().PadLeft((int)Math.Log10(count2) + 1) + "回目 : " + measuredList[i]);
                }
                Console.WriteLine("平均 : " + measuredList.Average());

                //------------------------------//
                // 計測 StringBuilder
                //------------------------------//

                measuredList.Clear();
                Console.WriteLine("-------------------------------------------------------");
                Console.WriteLine("StringBuilderクラスで計測します。");

                GC.Collect(GC.MaxGeneration);
                for (int i = 0; i < count2; i++)
                {
                    measuredList.Add(MeasureTime_StringBuilder(count1));
                    Console.WriteLine((i + 1).ToString().PadLeft((int)Math.Log10(count2) + 1) + "回目 : " + measuredList[i]);
                }

                Console.WriteLine("平均 : " + measuredList.Average());

                //------------------------------//
                // 計測 StringBuilder + Append
                //------------------------------//

                measuredList.Clear();
                Console.WriteLine("-------------------------------------------------------");
                Console.WriteLine("StringBuilderクラス + Appendメソッドで計測します。");

                GC.Collect(GC.MaxGeneration);
                for (int i = 0; i < count2; i++)
                {
                    measuredList.Add(MeasureTime_StringBuilderAppend(count1));
                    Console.WriteLine((i + 1).ToString().PadLeft((int)Math.Log10(count2) + 1) + "回目 : " + measuredList[i]);
                }
                Console.WriteLine("平均 : " + measuredList.Average());

            }
            finally
            {
                Console.WriteLine("何かキーを押してください...");
                Console.ReadKey();
            }
        }

        /// <summary>
        /// stringクラスを指定された回数確保し、その時間を計測します。
        /// </summary>
        /// <param name="count">回数</param>
        /// <returns>時間(秒)</returns>
        static double MeasureTime_String(int count)
        {
            DateTime strT = DateTime.Now;

            for (int i = 0; i < count; i++)
            {
                string s = "";
                s = s + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
                Program.d_out = s.ToString();
            }

            DateTime endT = DateTime.Now;

            return (endT - strT).TotalSeconds;
        }

        /// <summary>
        /// StringBuilderクラスを指定された回数確保し、その時間を計測します。
        /// </summary>
        /// <param name="count">回数</param>
        /// <returns>時間(秒)</returns>
        static double MeasureTime_StringBuilder(int count)
        {
            DateTime strT = DateTime.Now;

            for (int i = 0; i < count; i++)
            {
                StringBuilder s = new StringBuilder("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890");
                Program.d_out = s.ToString();
            }

            DateTime endT = DateTime.Now;

            return (endT - strT).TotalSeconds;
        }

        /// <summary>
        /// StringBuilderクラスを指定された回数確保し、Appendメソッドで文字列を指定します。その時間を計測します。
        /// </summary>
        /// <param name="count">回数</param>
        /// <returns>時間(秒)</returns>
        static double MeasureTime_StringBuilderAppend(int count)
        {
            DateTime strT = DateTime.Now;

            for (int i = 0; i < count; i++)
            {
                StringBuilder s = new StringBuilder();
                s.Append("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890");
                Program.d_out = s.ToString();
            }

            DateTime endT = DateTime.Now;

            return (endT - strT).TotalSeconds;
        }
    }
}

汚いとか言わない。

実際にやってみた。

実際に動かしました。スペックは以下の通り。

  • CPU: Atom Z3775 (1.46GHz 4core)
  • メモリ: 2GB

f:id:yuzutan_hnk:20170226021055p:plain:w300

やっぱり、string型のほうがオーバーヘッドは少ないみたいですね。

追記 2017/02/26 実験に使ったスペックを記述していなかったので追記。

内臓HDDのUbuntuをUSBメモリのGrub2から叩く。

非常に初歩的なことですが、かなり調べて納得がいったようないってないようなところまで行きついたので、メモっておきます。

今回は 起動できればいい というスタンスで行くので、詳しいことは全くわかりません。これから勉強します。

環境

今回試したのは、以下の環境。

目標は簡単なことです。 USBのGrub2 から SATAのHDDのUbuntuを起動する だけです。普通はしないけど。

なんでこんなまどろっこしいことがしたいかというと、Ubuntuを内臓HDDにインストールしたまではよかったんですけど、UEFIが入っているはずのGrub2を認識してくれないのです。もしかしてUEFIモード対応のBIOSだったのかこれ?

順序

あくまで理論的な話。

Grub2が起動すると、規定ではOSを選ぶメニューが表示されます。

f:id:yuzutan_hnk:20170217014440j:plain:w300

このとき、メニューで「c」キーを押すとシェル画面に遷移します。この画面ではbashライクな初歩的なコマンドにより、ドライブの中身を確認したりOSをブートさせたりできます。

f:id:yuzutan_hnk:20170217014441j:plain:w300

この機能を使って、実際にUSBのGrub2のメニューには出てこない、内臓HDDのUbuntuを起動させます。

手順

まずは確認

まずは、ディスクの名前を確認します。これは ls コマンドで一覧を取得できます。

f:id:yuzutan_hnk:20170217014442j:plain:w300

grub> ls
(memdisk) (hd0) (hd0,msdos1) (hd1) (hd1,gpt4) (hd1,gpt3) (hd1,gpt2) (hd1,gpt1) (hd2) (hd2,msdos1)

現在起動に使っているUSBは (hd0) として認識されています。試しに、 (hd0) の情報を表示してみます。

f:id:yuzutan_hnk:20170217014443j:plain:w300

なんか、大量にエラーが出ていますが、今回は 起動ができればいい ので無視します。一応、最後の一文がそれっぽい結果になっています。

grub> ls (hd0)
Device hd0: No known filesystem detected - Sector size 512B - Total size 7834624KiB

確かに容量が8GBに近いですので、起動USBと考えて間違いないでしょう。

次に、起動するUbuntuの入ったHDDを確認します。

たぶん見るからに (hd1) っぽいです。なぜかというと、grub上(というかLinuxでは全般に)では、 MBRパテーションテーブルは msdos として表示 されますし、 GPTパテーションテーブルは gpt として表示 されるからです。起動したいのはGPTのHDDです。

f:id:yuzutan_hnk:20170217014443j:plain:w300

grub> ls (hd1)
Device hd1: No known filesystem detected - Sector size 512B - Total size 976762584KiB

案の定ですね。これが1TBのHDDです。

では、今度はUbuntuを起動させるため、Linuxカーネルの配置を確認します。パテーションの1つめはESPなので、2つめのファイル一覧を取得します。

f:id:yuzutan_hnk:20170217014444j:plain:w300

grub> ls (hd1,gpt2)/
lost+found/ boot/ hdata/ etc/ media/ var/ bin/ dev/ home/ lib/ lib64/ mnt/ opt/ proc/ root/ rules.d/ run/ sbin/ snap/ srv/ sys/ tmp/ usr/ vmlinuz initrd.img cdrom/ initrd.img.old vmlinuz.old

Ubuntuのルートですね。さて、これでUbuntuを起動させられるだけの情報は整いました。

え?カーネルのフルネームを確認できていないって?そうそう、なんだか知りませんが、 システムのルートにシンボリックリンクが張ってあるのでそれを使えば問題ない そうです。

起動する

では、実際に起動します。次のコマンドを打って、終わり。

grub> set root=(hd1,gpt2)
grub> linuxefi /vmlinuz root=/dev/sda2
grub> initrdefi /initrd.img
grub> boot

f:id:yuzutan_hnk:20170217014445j:plain:w300

linuxefi コマンドで、起動するLinuxカーネルを指定します。今回はシステムルートにある vmlinuz というシンボリックリンクを使って指定しています。これがない場合は、 boot/ 以下にある本体をフルネームで指定します。

同時にシステムのルートを指定します。 root=/dev/sda2 の部分です。多くのサイトの解説では、今回のような (hd1,gpt2) をルートとしたい場合、 /dev/sdb2 とするのが一般的だそうです。たしかに (hd0) があるので、それを sda とすると、 (hd1)sdb になります。理屈はわかります。

しかし、 それでは起動しませんでした 。憶測ですが、もしかしたら起動時にカーネルからデバイスの再スキャンが行われて、カーネルが認識した順番がGrubの認識した順番と違う、という現象が起こっているのかもしれません。全く分からない。

次に initrd コマンドですが、どうもモジュール等を含むデータをメモリに読み込むためのコマンドのようです。よくわかりませんが、これも initrd.img というシステムルートにあるシンボリックリンクを使います。ない場合は、 boot/ 以下にある本体をフルネームで指定します。

最後に boot コマンドでブートさせます。

f:id:yuzutan_hnk:20170217014446j:plain:w300

ちなみに、UEFI環境でない場合は、efiがついていないコマンドでブートします。UEFIでも使えるので、実質どちらでもいいのでは…?

grub> set root=(hd1,gpt2)
grub> linux /vmlinuz root=/dev/sda2
grub> initrd /initrd.img
grub> boot

最後に

f:id:yuzutan_hnk:20170217014447j:plain:w300

無事に起動できました。grubのシェルを直で触るなんて初めてで、いろいろ試行錯誤して、起動できたときは本当に感動しました。大歓喜でした。

今回は本当に 起動できればいい というスタンスなので、あまり深入りはしませんが、これで調べるべき対象が一つ増えた気がします。

やっぱりLinuxは楽しい(まだ何もわかっていないのに)。

C#でJavascriptみたいな即時関数を実行する

個人的には、「即時関数」より「即時構文」というほうがしっくり来ます。

名づけ親の本では「即時関数パターン」とされているので、それでもしっくり来ます。

「即時関数」じゃ、少し足らない気がします。

Javascriptでよく使われる即時関数について

まず即時関数というものが何者かを解説します。

ずばり、匿名関数をその場で実行する書き方です。

普通は関数を別に定義して、名前()で呼び出すのが普通ですが、Javascriptでは関数が立派なオブジェクトですので名前をつける必要がありません。そこで、名前を付けずにその場で実行してしまおうという書き方になります。なんとも野心的。

書き方

例1:

var x = (function() { return 1; })();

上記では、xに 1 が代入されます。つまり、function { return 1; }が実行され、その結果が代入されます。

例2:

var x = (function(num) {
    return function(innNum) { return innNum * num; };
})(5);

上記では、xにはfunction(innNum) { return innNum * 5; }が代入されます。

一見「なんだこれ?」ですが、中でfunctionを返しているというところに注目してください。

中のfunction文は即時関数を使っていないので、実行されません。すなわち匿名関数の定義のみ行います。

そして、Javascriptでは匿名関数の定義は評価時に行われるという特徴があります。今回の場合、クロージャの影響でnumに 5 が入っていることを参照してから定義するため、返される匿名関数内のnumは 5 に固定されるのです。

C#で書く

C#は最近、匿名関数だのラムダ式だの、Javascript関数型言語パラダイムを意欲的に取り入れているため、同じように即時関数を書くことができるようです。

Javascriptで挙げた2つの例を、C#で書き直してみます。

例1:

int x = new Func<int>(() => 1)();

C#Javascriptと違って静的な型付け言語のため、匿名関数も型にはめてあげないといけないようです。new Func<int>を省略すると「メソッド名が必要です」というコンパイルエラーが発生します。

例2:

Func<int, int> x = new Func<int, Func<int, int>>((num) => new Func<int, int>((innNum) => innNum * num))(5);

Func<>がとんでもなく多い。さらに、引数と戻り値と型をいちいち指定しなければならない。この場合はちょっと無理がありそうですね。

関数を返すような処理をしなければ、一応使えそうな書き方ですね。

初心者が初めてグラボを取り付けたお話

去年の暮れ、はじめてグラフィックボードなるものをパソコンに取り付けました。

理由としては、年賀状の作成に使っているInkscapeのフィルタ機能が極端に重いので、

「もしかしてグラボつけたら速くなるんじゃね?」

という安直な思いの元、購入したのでした。

結果速くはならなかったんですけど。

初めてグラボを買う

今回、購入したグラボはこちら↓

f:id:yuzutan_hnk:20161224125551j:plain:w300

GeForce GTX 1050です。Tiではないのでビデオメモリは2GBです。1050にしては特徴ガン無視の補助電源ありのモデルです。

価格として15000円強。普通の1050なら10000円ちょっとで買えるものなのですが、HDMIが3本出力できるというところで選びました。今のところ2つしか使いませんが、ちょうど2つなんでいうグラボはなかったんですね。

早速開ける

f:id:yuzutan_hnk:20161224125539j:plain:w300

半分くらいが発泡スチロール。そして本体は黒みがかったビニールに包まれています。

f:id:yuzutan_hnk:20161224125528j:plain:w300

取り出しました。まあまあの重さです。

大きなファンとごついプラスチックケース。この中に基盤が収まっているんですね。

グラボって無駄にかっこいいよね

f:id:yuzutan_hnk:20161224125503j:plain:w300

たしかにHDMIが3本、DisplayPort、DVIがあります。すべてキャップが付いてます。

これがパソコンの背面に出てくる形になるんですね。

取り付け準備

まず、PCケース背面にあるカバーを取り外します。

f:id:yuzutan_hnk:20161224125931j:plain:w300 f:id:yuzutan_hnk:20170104010713j:plain:w300

ねじで止まっているので、ドライバーを使って外します。外すと、外側から中が見えるようになります。

f:id:yuzutan_hnk:20161224125909j:plain:w300

まずは練習

初めてパソコンにパーツを増設するため、一応練習も兼ねて小さな基盤も購入しました。

f:id:yuzutan_hnk:20161224125516j:plain:w300

こちらはPCI Express x1に指すとUSBの口が4つ(?)増えるものです。背面にAポートが2つ、そしてヘッダが1つ増えます。もともとのUSBの口が足らなくなってきたのもあったので、購入しました。

f:id:yuzutan_hnk:20161224125856j:plain:w300

端子をあわせて……

f:id:yuzutan_hnk:20161224130440j:plain:w300

挿す。

すると、背面にちょうどUSBの端子が見えるようになります。

f:id:yuzutan_hnk:20161224130426j:plain:w300

最後に、このUSB基盤は補助電源にSATAの口があるため、ハードディスク用のSATA電源をつなぎます。そして、先ほど外したねじでカバーの部分を固定します。

f:id:yuzutan_hnk:20161224130411j:plain:w300 f:id:yuzutan_hnk:20161224130357j:plain:w300

案外、簡単じゃない?

グラボを取り付ける

次にグラボを取り付けていきます。

グラボも同じ要領で、端子を合わせて挿すだけです。ただし本体が分厚いため、斜めにして確認することは難しいです。また先にUSB基盤を取り付けてしまったため、横から確認することも難しいです。

とりあえず勘で挿したらうまくいきました。なんとか。

f:id:yuzutan_hnk:20170104010915j:plain:w300

PCI Express x16 は1つしか使いませんが、背面は2スロット使います。

f:id:yuzutan_hnk:20161224130921j:plain:w300

グラボの補助電源は、PCI Express 補助電源コネクタを使用します。

基本的に6ピン構成、電力が大きいものだと8ピン構成のものもあります。

f:id:yuzutan_hnk:20161224130859j:plain:w300

端子を合わせて…

f:id:yuzutan_hnk:20161224130848j:plain:w300

挿します。

グラボもカバー部分をねじで止めます。

f:id:yuzutan_hnk:20161224130837j:plain:w300

以上で完成です。繋ぐだけです。本当に簡単ですね。

ドライバインストール

ハードが完成したので、今度はソフト側を構成します。

グラボを挿すと、自動的にビデオ出力はグラボ側から出るようになります(オンボードは使えなくなります。使える場合もあるそうですが)

ただし初回はドライバがインストールされていないため、互換モード(640x480?)で出力されます。

f:id:yuzutan_hnk:20161224131244j:plain:w300

このような付属のCDがあればそこから、インターネットにつながっていれば公式サイトから落とすことができます。

が、ここで予想外の出来事が。

f:id:yuzutan_hnk:20161224131259j:plain:w300 f:id:yuzutan_hnk:20161224131328j:plain:w300 f:id:yuzutan_hnk:20161224131344j:plain:w300

自動でドライバを認識してくれた!!

このあと、再起動すると普通にネイティブ解像度で出力され、環境構築が完了していました。うーん、なんだか微妙な気持ち…

ベンチマーク

Plag and Playの影響なのか何なのかはわかりませんが、すぐに使えるようになったので早速ベンチマークします。

今回使ったのは、ドラゴンクエスト10PSO2ベンチマークソフトです。

ゲームが本来の目的ではないので、一応簡単にできればいいかなと…

ドラクエ10

  • 設定
    • 画質 : 最高画質
    • 解像度 : 1920x1080
    • フルスクリーン
  • その他スペック
    • CPU : i7-6700
    • メモリ : 16GB

↓(装着前) オンボード Intel HD Graphics
f:id:yuzutan_hnk:20161218021142p:plain:w300

↓(装着後) GeForce GTX 1050
f:id:yuzutan_hnk:20161218021141p:plain:w300

結構上がりましたね。

ドラクエ10はそもそも、オンボードでも結構快適に動いていたんですよね。スコアはスコアですが、結果としても「標準」として出ているように、そこまで高スペックを求めなければ十分遊べそうな環境でした。

しかし、やはりグラボを載せると安定さが違いますね。ムービーの見た目はそこまで変わりませんでしたが、たぶん戦闘中などパーティクルが多くなった時のカクツキが少なくなる(というかなくなる)気がします。

PSO2

  • 設定
    • 画質 : 6
    • ゲーム設定-描画設定 : すべてON
    • ゲーム設定-詳細設定 : 50(max)
    • 解像度 : 1920x1080
    • フルスクリーン
  • その他スペック
    • CPU : i7-6700
    • メモリ : 16GB

↓(装着前) オンボード Intel HD Graphics
f:id:yuzutan_hnk:20161218021144j:plain:w300

↓(装着後) GeForce GTX 1050
f:id:yuzutan_hnk:20161218021145j:plain:w300

破壊的に変わってますね

オンボードだとFPSが常時20前後、影や反射などの描画がおかしかったりと、とてもゲームができる環境ではありませんでした。

しかしグラボをつけると、もうカクツキから完璧に解放されたと言えます。すべてのエフェクトをつけてもコマ落ちすることはなく、常にFPS120あたりを推移していました。どうせ今のディスプレイは最高60Hzあたりでしょうから、申し分ありません。

結果

グラフィック性能はものすごく上がりました。これでゲームははかどりそうです。

しかし、実際にInkscapeで年賀状を作るときの処理は、まったくもって変わりませんでした。あれはCPUに描画処理をすべて任せているのでしょうね。

同じように、いつも遊んでいるK-shoot maniaという音ゲーも、DirectXを使ってはいますが肝心の譜面部分がソフトウェア描画になっているので、全く変わりませんでした。

やっぱり、普段からゲームをしない人にとっては不必要なんでしょうかねぇ…。