プログラムdeタマゴ

nodamushiの著作物は、文章、画像、プログラムにかかわらず全てUnlicenseです

Razer Tartarus V2 ハードは完璧、ソフトは酷すぎる

>追記:Razer Tartarus V2をRazer synapse3無しで動かす


 Razer Tartarus V2という左手用キーボードを購入したので、そのレビューというか、愚痴。

 最近、Logicool アドバンス ゲームボードG13rの調子が悪く、新しい左手用キーボードが必要になりました。
 で、Razer Tartarus V2というゲーミングキーボードのフィット感がヤバく、その場で衝動買い。お値段1万ちょっと。

 なお、当方PCでゲームはしません。CADや3Dモデリングに使うつもりで購入しました。


 この親指部分がとても気に入りました。


 なお、注意点としては、この十字キーは、目で見て右側が上ボタン、左側が下ボタン、上側が左ボタン、下側が右ボタンになっています。
 親指を押し込むと上、引くと下という思想の設計なのでしょう。ユーティリティで変更出来るので特に気になりませんが。

 

 全体の見た目。

 個人的にはホイールは若干位置的に回しにくく、15番のキーの位置にホイールが欲しいかなと思います。
 
 

 ホイールは若干不満がありましたが、全体的に押しやすく、安定感があり、G13rの親指のレバーみたいに細くないので強く押しても痛くなく、とても良い作りだと思います。
 

ソフトが壊滅的

 

 この手のキーボードはユーティリティで対象アプリケーションに合わせて、キーの機能を変更する必要があります。
 そのユーティリティはTartarus V2をUSBにさした時点で自動的にインストール開始されます。ちょっと時間がかかるけど、楽で良い。

 と、ご機嫌だったのはここまで


 ………ふぁっ?

 ちょっと待ってほしい。アカウント登録してサインインしなければ設定が出来ない。ローカルだけで使うつもりなのに。

 何故、一々アカウントを登録せねばならないのか。一ユーザーとしてはデバイスを使いたいだけだ。1万円払ってなお、まだ個人情報が欲しい、よこせと言われている様にしか思えない。

 この時点で不信感が非常に漂い始める

 ここで、ちらっとタスクマネージャーを見てみる。

f:id:nodamushi:20180616114135p:plain

 うぅん!?合計メモリ使用量360Mb?高々キーボードのユーティリティの為に!?

 私の貧弱なPCは16Gbしかメモリ積んでないから、これの為だけに2%強のメモリ使用量だ。
 大した量じゃないと言えば大した量じゃないが、Firerox、Clojureの開発やら、GradleやらEclipseやVisual Studio、仮想マシン、RAM Disk、Emacs、Inkscapeなどのヘビー級のプロセスを何個も起動して放置してる私としては、メモリが不足がちなので、ちょっと勘弁して頂きたい。まぁ、不足しがちな主原因はRAM Diskですが。

 うぅわぁ~………


 かなりゲンナリしながら渋々アカウントを取得し、設定をしてみました。

 設定ユーティリティはよく出来ていると思います。特段迷うこともなく私のやりたい設定は出来ました。若干マウスクリックが多くて面倒くさいと思ったけど。
 光るのが嫌いな私としては、ライティングをオフに出来る点も素晴らしい。(というか、何で何でもかんでも光らせようとするんだろ。)

 

 さて、ここで気になるのは、この重たい常駐ソフトを起動していなければこのデバイスが使えないのかどうか。
 何の情報を送ってるのか知らないが(これかな?)、Amazon AWSと通信してるし気持ち悪いので出来るなら切りたい。

 タスクバーのアイコンを右クリックするとメニューの中に「すべてアプリを終了する」というアイテムがあったのでこれをクリック。

f:id:nodamushi:20180616121618p:plain

 この状態で色々設定したホームポジションの横一列を打ってみると「asdf」となった。
 残念ながら、これはデフォルトのキーバインドです。ソフトを起動していなければ動かない

 嫌だなぁ………。


 しかし、ここでさらにタスクマネージャーを見て驚愕の事態に気がついた。
f:id:nodamushi:20180616122349p:plain
注:「すべてのアプリを終了する」を押した後


 終了してない。しかも、タスクを殺しても、勝手に復活する。
 Game Manager ServiceとCentral Serviceが相互に起動し合う形になってるのか、これら二つが復活するのだ。
 それはもう、ゾンビプロセスってこういう意味だったっけ?てレベルで復活する。Cortanaレベルで復活する。

 Game Manager Serviceは高速で再起動するので、Central Service→Game Manager Serviceと殺せば、殺せるが、ちょっともたつくとゾンビアタックされる。

 

 神奈川県警サイバー犯罪対策課によると、WebページのJavaScriptで30%程度のCPU計算能力を使って採掘をする行為は、人格を疑うレベルの犯罪行為らしいので、私の意図に関係なく150Mbの記憶容量を奪い、しかも通常に終了する手段を持たないこれは警察レベルで言えば、ウィルスだと言っても良いはずだ。この記事のタイトルは「Razer TARTARU V2 ハードは完璧、ソフトはウィルス」と書きたいぐらいだ。

 

結論

 

 ハードは、正直ソフトの悪印象を考慮した上で言って、素晴らしい。強いて言うなら、ホイールの位置と、親指にもう2個程ボタンが欲しいぐらいか。
 3Dモデリング、CAD、ペイントソフト、さまざなま場面で活躍出来るポテンシャルを持っている。
 私が使用していたLogicool ロジクール アドバンス ゲームボード G13rと比較しても、使いやすく、非常にハードだけはお勧め出来る。1万円の価値はある。

 だが、ソフトを込みで考えると、ちょっと考えるべきだ。勝手に情報送るし、重いし、終了出来ないし。さらに、[糞ソフト]Razer Synapse3 について語るスレ[プロセス激重]での報告を見ると、様々なバグが存在する様だ。

 ちなみに、私はスリープから復帰するとRazer Tartarus V2のプロファイルがデフォルトに戻り、変更が全く効かなくなるという症状が出ている。再起動しないと直らない。スリープとは何だったのか。

 私は衝動買いし、自力でソフトは解決(追記参照)することでTartarus V2は神と化したが、買うかどうかは情報をよく集め、よくよく吟味してから購入することをお勧めする。

>追記:Razer Tartarus V2をRazer synapse3無しで動かす

 

nio.Pathの小さなユーティリティライブラリを公開してみた

 Google guava………便利だよね。Appache Common………便利だよね。

f:id:nodamushi:20180506204944p:plain

 ………まぁ、デカいとは言わないけど、ちりも積もればなんとやらだよね?


f:id:nodamushi:20180506204654p:plain

 ………でかすぎね?

 そう、私は言いたいのだ。世の便利なJarファイルはデカい。デカすぎる。
 ちょっとした内製ツールをウッカリ慣れてるJavaやClojureで作ってしまって、他の人達が単体で使える様に共有サーバー(遅い)へzipして置くと、なんだかんだ言って容量を食うのだ。今、この文章を打った時に、「なんだかんだ言って面積を食うのだ」と書いてしまった私は論理に毒されてきている気がするぞ。

 

 果たしてGoogle guavaの一体どれほどのクラスを使ったことがあろうか。Appache Common IOのどれほどを使ったことがあろうか。Eclipse Collectionの、ホゲホゲの、モゲモゲの、ピヨピヨの世に数多あるライブラリの一体何パーセントを使っているというのだ。恐らく数kb分しか使ってない。そのために100kb?ウンMb?肩身が狭い!

 
 

github.com.nodamushi:common.paths


 と、私が叫んでいると言うことは、案外同じ事思ってる人って居るんじゃねぇの?ってことで、普段よく使ってるPathに関する関数を集めて、まとめてみた。GitHub - nodamushi/common.paths: A small utilities for java.nio.file.Path.

 コンセプトは地味でコンパクトだ。
 クラスは内部クラスを除けば地味に一個しかない。Jarファイルは地味に13kbyte。まぁ、これぐらいなら地味に許されてもいいんじゃないだろうか?

 あと、地味にnio.Pathをそのまま使うライブラリってあまりない気がする。Stringか、Fileだよね。

 

地味にMavenに置いた

 私が作った物使う阿呆いねぇだろ、ってことで、何か作ってもソースコード公開するだけで放置がデフォルトなんだけど、今回のは地味に個人的に何処でも使いたいので、地味に登録してみることにした。

<dependency>
  <groupId>com.github.nodamushi</groupId>
  <artifactId>common.paths</artifactId>
  <version>1.0.0</version>
</dependency>

 初めてやってみたが、ぶっちゃけ、置けないだろって思ってたら、置けてしまった。びっくりだ。
 repositoriesを書かなくても、dependencyだけで、ネットから自分のライブラリが勝手にダウンロードされるというのは、妙な気分だね。

 参考にしたページ:

 GPGはMSYS2ので普通にいけた。

後の祭り

 私は普段、ライブラリ系のプロジェクトのartifactIdはgroupIdとくっつけると基準パッケージになるようにつけてます。パッケージ名がhoge.moge.piyoで、groupIdがhogeなら、artifactIdはmoge.piyoって感じ。一律に付けられるからこの命名は楽

 なんだけど、よくよく考えたら一般的にはhamcrest-allとかみたいになってるんだよね。
 後で気がついたぜ。

 まぁ、もうやっちゃったモンは仕方がない。気にしないぜ。(´・∀・`)

地味に便利な関数達

 地味に便利な関数を簡単に紹介していこう。

 

newBufferedReader

 地味によく使う。Files.newBufferedReaderと違って、UTF-8のBOMを自動的に無視するBufferedReaderを作成する。ついでにUTF-16にも対応した。

try(var r = NPaths.newBufferedReader(utfFile, StandardCharset.UTF_8){
  var line = r.readLine(); //自動的にBOMは無視される
}

 

replaceExtension

 地味に割と使う。Pathのファイル名から拡張子だけ変更するときって稀によくある。

var txt = Paths.get("/hoge/piyo.txt");
var csv = NPaths.replaceExtension(txt,"csv"); // /hoge/piyo.csv
var ext = NPaths.getExtension(txt); //拡張子取得もあるよ。

 ファイル名の先頭に文字追加したり、っていうのもあるよ。

 

getParent

 地味に意識して使う。Pathの親を取得する時に、決してnullを返さない。
 面倒くさがってpath.getParent()ってやってて、findBugもせずにヌルポが発生した時の悲しさよ。

var path = Paths.get("a.txt");
var nullpath = path.getParent();//null
var nonnull = NPaths.getParent(path); // empty path
// parentがnullでも大丈夫なresolve
resolve(nullpath"b.txt"); // b.txt

 
 

walkFiles

 極稀に使う。FileVistorのvisitFileだけを実装することで動かす。潜るディレクトリの深さも指定可能。
 とりあえずディレクトリを再帰的にファイルを集めたいとか、再帰的にファイルだけ何か処理したい時に便利。

List<Path> list = new ArrayList<>();
NPaths.walkFiles( dir, -1 ,(path,attr)->{
  list.add(path);
  return FileVisitResult.CONTINUE;
});

 

iterator

 あんま使わないかな。
 デフォルトのPathのイテレータとの違いは、ルートも一つの要素と見なす。デフォルトのイテレータの様に名前だけにすることも可能。

for(Path p :NPaths.iterator( Paths.get("C:/a/b/c") ){
  //  p:
  // 1回目: C:/
  // 2回目: C:/a
  // 3回目: C:/a/b
  // 4回目: C:/a/b/c
}

 

まとめ

 もっと小っちゃいモジュールで世の中が溢れると、良いですね。
 といいつつ、結局面倒くさくなって大きな奴を使うんじゃないんかな。

EmacsのIronyがタイムアウトする場合の対処法

 EmacsのIronyがサーバーエラーも何も返さず、タイムアウトするという現象に悩み、何とか解決しました。

バージョン

Emacs25
Irony :20180418

現象

 company-ironyで補完を仕様とすると、サーバーエラーも返さず、タイムアウトする。タイムアウトの時間を10秒など伸ばしても変化無し。

 Irony Serverを単体で動かせば、正常に動作する。

 

原因

 start-process-shell-commandで使われるshellがtcshである。
 (list-processesでプロセス一覧出して、Ironyのコマンドがtcshから始まっているかいないかで確認可能)

 

解決方法

 適当にbashなどのshellに変更する

(setq shell-file-name "/bin/bash")

 

 ひとまず私はこれで直りました。

JAXBをEclipseLink MOXyに移行する

 JavaでXMLを処理しようと思えば、やっぱJAXBですよね。便利ですもんね。

 ですが、このJAXBがJava9で非推奨になり、早くもJava11で完全削除されることになりました。早くねぇ?1年しかないんですけどぉ?
 けっこう呑気していたnodamushiも一瞬巨大に見える程のOracle圧力にはビビった!!

 というわけで、太った 重い腰をいい加減あげて、脱JREのJAXBをしてみました。


EclipseLink MOXy

 脱JREのJAXBと言いましたが、何も脱JAXBをする訳ではありません。外部実装に移行します。

 その選択肢の一つがEclipseLink MOXyです。(選択肢の一つと言いましたが、他の選択肢があるのか知りません。)

 MOXyはXMLだけじゃなくて、JSONのバインディングにも対応しているそうです。
 また、XSD→Javaに変換するコンパイラもちゃんとあります。(jaxb-compiler)

 今の所、xjcはJDKに付属していますが、JDK11で無くなると思うので、EclipseLink Installer Zipをダウンロードして、適当な場所に展開し、binディレクトリにパスを通してください。
 (展開するだけな気がするんだけど、Installerってどういうことなんだろ?)

f:id:nodamushi:20180401171240p:plain:w320

XML Schema をJavaクラスに変換する


 試しに、XML Schemaファイルperson.xsdを作成し、Javaクラスに変換してみます。構造は以下の図の様になっています。

f:id:nodamushi:20180401173218p:plain

<?xml version="1.0"?> 
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <xsd:element name="persons">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element ref="person"  minOccurs="0" maxOccurs="unbounded"/>
      </xsd:sequence>
    </xsd:complexType>
  </xsd:element>

  <xsd:element name="person">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element name="name" type="xsd:string" minOccurs="1" maxOccurs="1"/>
        <xsd:element name="age"  type="xsd:unsignedInt" minOccurs="0" maxOccurs="1"/>
        <xsd:element name="sex"  type="sexType" minOccurs="0" maxOccurs="1"/>
      </xsd:sequence>
      <xsd:attribute name="id" type="xsd:string" use="optional"/>
    </xsd:complexType>
  </xsd:element>
  
  <xsd:simpleType name="sexType">
    <xsd:restriction base="xsd:string">
      <xsd:enumeration value="female"/>
      <xsd:enumeration value="male"/>
    </xsd:restriction>
  </xsd:simpleType>
</xsd:schema>


 上記のperson.xsdをJavaに変換します。
 xjcとの差を確かめる為に両方で変換してみました。(person.xsdはsrc/main/xsdディレクトリに配置しています)

xjc -no-header -encoding utf8 -d src/main/java -p test.xjc src/main/xsd/person.xsd
jaxb-compiler -no-header -encoding utf8 -d src/main/java -p test.eclipselink src/main/xsd/person.xsd

 生成されたファイルのdiffをとり、違いを見てみました。

xjc EclipseLink diff
test/xjc/ObjectFactory.java test/eclipselink/ObjectFactory.java packageの名前が違うのみ
test/xjc/Persons.java test/eclipselink/Persons.java packageの行のみ違う
test/xjc/Person.java test/eclipselink/Person.java packageの行のみ違う
test/xjc/SexType.java test/eclipselink/SexType.java packageの行のみ違う
test/eclipselink/jaxb.properties xjcでは生成されない


 上記の結果を見る限り、生成結果は全く同じなようです。安心してそのまま移行出来ますね。

 なお、EclipseLinkのほうでは生成されたjaxb.propertiesファイル(中身は以下の一行)は、XMLを読み込み、各クラスのデータにバインドする処理を行うクラスをどこから取得するのかという設定ファイルになります。

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory

 JDK11からはJAXBが同梱されない為、この設定ファイルは必須になります。


 

 

MOXyをプログラムで使ってみる

 上記で生成したpersonクラスを実際にXMLを読み出して、バインドしてみます。

 環境は以下です。

  • JDK:Java10
  • ビルドツール:Gradle

 まずは、build.gradleのdependenciesに以下の二行を追加します。versionは適宜変更してください

compile group: 'javax.xml.bind', name: 'jaxb-api', version: '2.3.0'
compile group: 'org.eclipse.persistence', name: 'org.eclipse.persistence.moxy', version: '2.7.1'

 

 gradle initで生成されたAppクラスを以下の様に実装。
 長々と書いていますが、やってることは単純。

  1. XMLを読み込んで、xjcとjaxb-compilerで生成したクラスにバインド
  2. test.xjc.Personとtest.eclipselink.Personでは、同じクラス名で使いにくいので、App内で定義したPersonクラスに変換
  3. System.out.printlnで出力
  4. エラーがあった場合はFailとだけ表示
import java.io.File;
import java.lang.reflect.Method;
import java.util.List;
import java.util.stream.Collectors;
import javax.xml.bind.JAXB;

public class App {

  public static void main(String[] args) {
    File xml = new File("./src/test/resources/test.xml");
    try {
      System.out.println("-------XJC------------------");
      loadAndPrint(xml,test.xjc.Persons.class);
    }catch(Exception e) {
      System.out.println("Fail");
    }
    try {
      System.out.println("--------EclipseLink---------");
      loadAndPrint(xml,test.eclipselink.Persons.class);
    }catch(Exception e) {
      System.out.println("Fail");
    }
  }
  
  public static void loadAndPrint(File xml,Class<? extends Object> clz)throws Exception{
    Object persons = JAXB.unmarshal(xml, clz);
    List<Person> person = toPersonList(persons);
    person.forEach(System.out::println);
  }
  
  public static class Person {
    public String name,sex,id;
    public Long age;
    public Person(String name, Long age, Object sex, String id){
      this.name = name; this.age = age;this.id = id;
      this.sex = sex==null?null:sex.toString();
    }
    @Override public String toString(){
      return String.format("person:[id=%s],name=%s,age=%d,sex=%s",
          id,name,age,sex);
    }
  }
  
  @SuppressWarnings("unchecked")
  private static List<Person> toPersonList(Object persons) {
    return ((List<Object>)get(persons,"person",List.class)).stream()
        .map(p->new Person(
            get(p,"name",String.class),
            get(p,"age",Long.class),
            get(p,"sex",Object.class),
            get(p,"id",String.class)))
        .collect(Collectors.toList());
  }
  
  private static String firstUpperCase(String str) {
    if(str.length()==1)return str.toUpperCase();
    return new StringBuilder(str.length())
        .append(Character.toUpperCase(str.charAt(0)))
        .append(str,1,str.length())
        .toString();
  }
  
  private static <T> T get(Object element,String childName,Class<T> clz){
    try {
      Class<? extends Object> c = element.getClass();
      String mName = "get"+firstUpperCase(childName);
      Method m = c.getMethod(mName);
      m.setAccessible(true);
      Object o = m.invoke(element);
      return clz.cast(o);
    }catch(Exception e) {
      throw new RuntimeException(e);
    }
  }
}

 

 10行目で直接指定しているテスト用のXMLファイルは以下の様な内容です。

<persons>
  <person id="1">
    <name>nodamushi</name>
    <age>19</age>
    <sex>male</sex>
  </person>
  <person>
    <name>Aoki Kei</name>
    <age>30</age>
  </person>
  <person>
    <name>Koike Yuka</name>
    <sex>femail</sex><!-- typo-->
  </person>
</persons>

 で、ビルドして実行すると以下の様になりました。

-------XJC------------------
Fail
--------EclipseLink---------
person:[id=1],name=nodamushi,age=19,sex=MALE
person:[id=null],name=Aoki Kei,age=30,sex=null
person:[id=null],name=Koike Yuka,age=null,sex=null


 

 XJC側は失敗していますが、EclipseLink MOXyの方は正常に読み込めていますね。
(EclipseLinkだけ読み込めたのはtest.eclipselink.jaxb.propertiesがあるからです。typo処理の違いではありません。なお、Java8で実行すると、両方ちゃんと読み込めます。)

 

 

まとめ

 

  • EclipseLink Installerをダウンロードし、binディレクトリにパスを通す。(jaxb-compilerが使える様になる)
  • GradleやMavenの設定ファイルにjaxb-apiEclipseLink MOXyをdependencyに追加する


 というわけで、あまり苦労することなく、EclipseLink MOXyに移行出来そうです。

 が、依存含めて外部jarファイルが5Mbもあるのはいかがなもんでしょうかね………。

GitBucketのシンタックス拡張プラグインを作ってみた

 はい、タイトルの通りです。

 GitBucketは入れやすいし、愛用させて頂いているのですが、大問題があるのです。
 それはシンタックハイライト機能がしょぼいと言うこと。とくに、Verilogとかね、悲惨なことになりますよ。
 別にGitBucketのシンタックスハイライトが有ろうが無かろうが、開発で困ることはないけど、ちょっとしたコミュニケーションツールとして、残念な感じになるのをどうにかしたかったんだよね。




 さて、GitBucketは構文ハイライトにGoogle Code Prettifyを使用しています。Prettifyは何も指定しなくても、何となく一般的な構文を使って、何となく良い感じにハイライトしてくれます。
 しかし、あくまでC言語っぽく何となくであって、より精度良くハイライトするには言語を指定する必要があります。
 言語はJavaやCなどのメジャーな言語は何もしなくても初めから定義されていますが、Lispやら、VHDLやら、CSSは外部ファイルとして定義されているので、利用するにはその外部ファイルを読み込ませてやる必要があります。ていうか、このデフォルトに入ってない奴らにScalaがあるんだけど、竹添様は気にならなかったのかな………

External Prettify Plugin

 上記の読み込み作業をGitBucketは行ってくれないので、

「拡張子を取得」→「言語を判断」→「必要なファイルを読み込む」

という処理をするプラグインを、土日でなんとかかんとか作ってみました。
 いやー、もう、さっぱどわからねぇ。Scala知らない、SQL知らない、HTMLもJavaScriptも分からないとかいう、なんの為に生きてるのか分からない人間のゴミクズが作った物なので、問題はいっぱいあるでしょうが、ひとまず公開。
 こういうプラグインないよね?あったら私の土日完全に無駄だったわ。

github.com


 なお、わかりやすさの為に拡張子と言いましたが、実際には後方一致です。というのも、「CMakeLists.txt」の様にファイル名全体で言語が決まる奴とか、「.p2.inf」の様に拡張子の中に.が入る奴とかいることに気がついて、後方一致に途中で変更しました。

 Google code prettifyに最初から組み込まれている主要な言語については、特に設定しなくても拡張子から判断する様にしています。

scalaの例:(違いが見にくい………)
f:id:nodamushi:20180219012750p:plain:w300

cssの例:
f:id:nodamushi:20180219013557p:plain:w350

 

設定をする

 件のVerilogなどは外部ファイルとしてですら、Google Code Prettifyには入っていません。VHDLはあるのに。APOLOとかいう謎の言語はあるのに。はぁ、萎えるわー………
 まぁ、無いなら作れば良いじゃない!

 

 というわけで、まずは、自分でシンタックスハイライトを作り、それを新しいレポジトリにあげます。
 自分で作りと言いましたが、今回はBooneJS さんという方が作ったのをそのまま持ってきました。(おい
f:id:nodamushi:20180219014101p:plain:w300

 あげたら、GitBucketのデフォルトプラグインのPagesを使ってJavaScriptとして読める様にします。(はじめからgh-pagesでpushしてもいいけど)
f:id:nodamushi:20180219014253p:plain:w300


 そしたら、以下のルールを設定します。

  1. .vで終わるファイルをv言語とする。(BooneJS さんがvという名前で定義していたから)
  2. v言語の場合、/root/mylangs/pages/lang-sv.jsを読み込む。(/root/mylangsは先ほど作ったレポジトリ)

f:id:nodamushi:20180219015545p:plain:w300

 なお、.v→vという定義はデフォルトでしてあるので、1は実は不要です。
 Verilogだけ贔屓です。( ^ω^)  だってVerilogの為に作ったんだもん!

 すると、妙に緑のハイライトが多かったVerilogのファイルが、綺麗にハイライトされる様になります。

f:id:nodamushi:20180219020039p:plain:w300


 やったね。
 ていうか、なんか、私って前もシンタックス系のプラグイン作ったよな………。この時はSDCC(組み込みC)で、今はVerilog(論理回路)か………どんどん低レベルになってるな。次はアナログ回路かな………

初心者が実験用Ubuntu仮想OSを立ててSSHで繋ぐまで

 サーバーとかWebを弄ってない私は、普段仮想OSっていうと単純にLinuxデスクトップを弄りたいだけ。基本的に、ホストOSとリモート接続する理由がなかったのですが、実験の為に仮想サーバーたてて、SSHで繋ぐまでをやってみました。

環境

 この記事は以下の環境での話です。

Ubuntuのインストール

 この辺は、まぁいつも通り変わらないので、さくっと。
f:id:nodamushi:20180214191644p:plain:w300
 

 適当に名前とメモリサイズを設定。
f:id:nodamushi:20180214192907p:plain:w300
 

 適当にハードディスクを設定。
f:id:nodamushi:20180214193143p:plain:w300
 

 ダウンロードしたisoをディスクに入れる。
f:id:nodamushi:20180214193403p:plain:w300
 

 ネットワークに移動し割り当てはNATのままで、使いそうなポートだけ、適当な番号にポートフォワーディングする。(高度で開いた項目の中にボタンがある)
f:id:nodamushi:20180214193617p:plain:w300
f:id:nodamushi:20180214193958p:plain:w300


 後は適当に起動設定とか好きな様にカスタマイズして、起動。日本語を選択。翻訳が完全じゃないとか言われたけど気にしない。
f:id:nodamushi:20180214195603p:plain:w300
 

 サーバーをインストール。地域とかキーボードとかはお使いの物をテキトーに選択。
f:id:nodamushi:20180214200324p:plain:w300
 

 適当にサーバー名を記入
f:id:nodamushi:20180214200638p:plain:w300
 
 本名を入れろというので、本名(saito-hideyuki)を入力。
f:id:nodamushi:20180214200802p:plain:w300
 

 アカウントのユーザー名に本名(ファーストネーム)を入れろというので、本名(kondo)を入力。
f:id:nodamushi:20180214200956p:plain:w300
 

 パスワードにセカンドネームを入れろと言われるので、本名(hideyo)を入力。お前の名前は脆弱だとケチを付けられるが、気にせず<はい>
f:id:nodamushi:20180214201033p:plain:w300
 

 で、その後色々聞かれるのでてきとーに答える。この辺からAltをフォーカスだけで持って行かれる様になったので面倒くさくなってキャプチャ無し。

  • 暗号化は面倒いのでノーセンキュー。
  • ディスクのパーティショニングもする意味ないので、全体を使うで。
  • プロキシ設定は空。
  • 自動的にアップデートしない
  • ソフトウェアの選択はスキップしたかったけど、出来ないので「OpenSSH server」を選択
  • ブートローダもインストールで良いんじゃないの

 で、インストールが無事完了。勝手に再起動すると、本名(kondo hideyo)を求められる。
f:id:nodamushi:20180214203007p:plain:w300
f:id:nodamushi:20180214203046p:plain:w300
 

 ルートのパスワードもhideyoだった。というわけで、インストール&起動完了
f:id:nodamushi:20180214203236p:plain:w300


 一応、OpenSSH Serverをaptでも入れておく。いやー、文字化けしてて何書いてあるか分からない。
f:id:nodamushi:20180214203457p:plain:w300

 

 というわけで、もう邪魔な仮想マシンは仮想デスクトップに移動してバックグラウンド化してもらおう。Window10の良いところだね。

 次に接続出来るかどうかを確認する。TeraTermを起動し、「localhost」、ポート番号「10022」にユーザー「kondo」、パス―ワード「hideyo」でログイン。これで、ホスト→ゲストの通信が出来る様になったぜぃ。

f:id:nodamushi:20180214225438p:plain:w300
f:id:nodamushi:20180214225555p:plain:w300

 

 でも、毎回パスワードを打つのは面倒くさいから、手持ちのid_rsa.pubを転送してから、.sshとauthorized_keysを設定して、ログインを簡単にしておく。

~$ mkdir .ssh
~$ chmod 700 .ssh
~$ mv id_rsa.pub .ssh/authorized_keys
~$ chmod 600 .ssh/authorized_keys

 うんうん。


 ホストのEmacsから仮想サーバーのファイルを操作する場合は/plink:kondo@localhost#10022:~/hoge.txtのようにして開ければおk。plinkはPuTTYへのパスを通しておくこと。
(id_rsa.ppkとPuTTYのDefault Settingsは作成しておく)


 よーし、繋ぐことが出来た。

 あ、なお、本名は私の本名ではないので悪しからず。

Chisel入門3~メリットデメリット~

f:id:nodamushi:20180203135601p:plain


 さて、入門1ではメリットだけを書きましたが、基本的に私はメリットだけ推して、デメリットを書かない論調が大っ嫌いです。デメリットがない文章はその時点で信用しません。

 というわけで、今回はメリットデメリットを紹介しようと思います。

 

 私が使ってみた上で、実感として感じるメリットは以下です。

  • IntelliJ IDEAといった統合開発環境の強力な補完機能が使える
  • Input,Outputの接続<>が強力
  • 接続を後から書ける
  • Wire、Regが本当に配線とレジスタという物理的な意味を持つ
  • Wire、Regといった要素をプログラマブルに生成出来る
  • 継承を利用することでOOPライクな思考が出来る

 

 逆に私が使った見た上で、これ駄目だろって感じたデメリットは以下です。

  • 新しい言語とパラダイムを学ばなければならない
  • 非同期リセットがない (※Chisel3では実装予定とはなっている) 
  • IOポートをVerilogに変換した時の命名を指定出来ない
  • エラーが超不親切
  • MSYSでVerilatorシミュレーションが出来ない

 
 

 では、まずはメリットから述べていきましょう。 

メリット

統合開発環境の強力な補完機能が使える

 Verilogを書く際の強力なエディタってなんなんでしょうか?私は正直よく分かりません。
 一応Emacs+Companyが私の基本開発環境ですが、Verilogはあんまり良い感じに補完してくれないですね。Visual Studio Codeもまぁ、頑張ってるけど、こう、C++とかJavaとかのように、これって感じじゃない。

 一方、Chiselは結局ただのScalaなので、IntelliJ IDEAやEclipseのScalaプラグインなどを入れれば統合開発環境の恩恵を受けることが出来ます。
 Chiselで久しぶりにScalaを触ったのですが、実用に十分な力があると言って良いです。Scalaが出たばっかの頃の使えないIDEのイメージが強くて、Scala(のIDE)なんて使えねーと想っていたのですが、今回Scala(のIDE)の評価を上方修正しました。

 

 わざわざ「Scala(のIDE)の評価」と、(のIDE)を薄く書いていますが、私は言語の評価と統合開発環境の評価はほぼ直結すると思っています。無論、ライブラリや、フレームワークなど、評価の全てではありませんが。

 そういう意味で、Chiselは良い選択肢でしょう。

 

接続記述が強力、抽象的に書ける

 <>については、既にChisel入門1であげたので、具体的に説明はしませんが、モジュールAのインスタンスaとモジュールBのインスタンスbの入力と出力を単純に繋ぎたい場合、以下の一文で済みます。

a.io <> b.io

 実際には、こんなに単純な接続なんてありませんから、もうちょっと構造を工夫するなどの考察は必要ですが、Chiselの接続は最後に書かれた物が有効などのルールも併用すれば、かなり短く書くことが出来ます。これはかなりメリットですよね。

 もう一つのメリットは、モジュールのインスタンスを宣言した後で、接続記述を書ける、と言う点をあげておきたいと思います。すなわち、インスタンス化記述と接続記述が分離されていることがメリットです。

val a = Module(new AModule)
val b = Module(new BModule)

a.io.INPUT := b.io.OUTPUT

 これにより以下のメリットが得られます。

  • a.io.INPUT等の様に書くことでどのインスタンスの処理をしているかが各行で明確である
  • 分離されたことにより、接続は接続でプログラマブルに処理出来る

 各行で明確だと、後から読む側としては、非常にありがたいですよね。百個ぐらいポートがあることも割とあるので、後から読みやすくなります。

 また、接続を分離して、プログラマブルに書けると言うことは、記述量の圧縮に繋がります。例えば、Module A,B,Cのインスタンスの接続を統一的に扱いたい場合を考えてみましょう。

 Verilogならこのようになるでしょう。

module D( ポート定義 );
  A a(ポート接続);
  B b(ポート接続);
  C c(ポート接続);
endmodule;

 上記のモジュールDを用意した後、必要な場所でDを実体化します。

D d1(ポート接続);
D d2(ポート接続);

 

 一方、Chiselだと以下の様になるでしょう。

val a1 = Module(new A),a2 = Module(new A)
val b1 = Module(new B),b2 = Module(new B)
val c1 = Module(new C),c2 = Module(new C)
//接続処理
def d(a :A,b :B,c:C) =>{
   //a,b,cの接続を書く
}
d(a1,b1,c1)
d(a2,b2,c2)

 

 大して変わらない様に見えますが、Verilogだと、Dという本来不必要なモジュールの階層が必要になります。後からa1の出力が他で必要だったとかなった場合、Dを修正する必要があり、あー面倒くさい。Chiselの方は必要ないですよね。
 なお、階層分けすることが悪い訳ではないので、やっぱりVerilogの方がいい、と言われるかも知れません。ここでは、あくまでmoduleを作らなくても、同じ接続を省略出来るという点に着目してください。

 さらに、RegやModule、Wireなどもプログラマブルに生成出来るので、配列やら再帰関数を使えば、複雑な物も割とさっくり書けます。Verilogだと、あれつないでこれ繋いで、あーーーとかなってるところです。

 継承によるOOPが使えるのもプログラム畑の人間からしたらメリットですね。

 

 

 ただし、これらは人によってはデメリットと捉えることには注意しておきましょう。なぜなら、Verilogの方が具体的だからです。

 例えば、以下のVerilogを考えてみます。

wire boutput;
AModule a (
  .INPUT(boutput),
  //他略
  );
BModule b(
  .OUTPUT(boutput),
  //他略
  );

 AModuleのaのINPUTは常にboutputに繋がります。そして、BModuleのbのOUTPUTも常にboutputに繋がります。a.io.INPUTが一体何処に繋がっているのか具体的に記述されていない、という現象は起こりえません。

 某staticおじさんよろしく、プログラミングの世界では抽象度の低いことは良いこととはあまり見なされませんが、ハードの世界は違います。何故なら、ハードは最終的に具体的な物(回路)になり、その具体的な物に対して検証をせねばならないからです。
 従って、抽象的であることは悪である、と言われた時、それを否定するだけの理屈を私は持っていません。同じ記述の素子であっても、性能ばらつくんだから。

 
 え、ソフトだったら?抽象化が絶対の正義で真理です。コピペマンはコテンパンにしてやんよ、かかってこい。



 

デメリット

 さて、メリット紹介が終わったら次はデメリットですね。がっつり行きましょう。
 
 

新しい言語とパラダイムを学ばなければならない

 Chisel入門1では、あたかもVerilogと一対一対応で書ける様な雰囲気で書きましたが、やっぱり別言語です。効率の良い書き方などを求める場合、どうしても学習からは逃げられません。
 (一応、inline verilogという逃げ道もあるけど)


 どんな言語や機能でもそうですが、これが最大の欠点ですよね。
 Verilogなんて何も変化してませんもんね。OVL対応とか、そういうツールの変化はあったかも知れないけど。え?System Verilog?さぁ………。

 どんな開発現場でも、新技術は導入したくないはずです。その新技術を使うことによるメリット、コストの評価も、信頼性の評価もしなければならないし、新技術なんてあっても良いことないです。技術なんて、少なくとも数百年ぐらいは同じ技術だけで食ってけるのが一番。イノベーションなんて打ち壊せー。ビバ、ラッダイト運動。


 学習を覚悟しなければならない、それはやっぱり一番大きなデメリットだと思います。

 

 

非同期リセットがない(実装予定)

 ちょーっとこれは論外なんじゃないですかねぇ。
 これはたぶんだけど、ChiselがメインターゲットとしてるのがFPGAだからっぽい雰囲気。

 一応、Chisel3.2で実装予定とのことだけど、元々Chisel3.0で実装予定が3.1になり、3.2に、3.3に3.4にとずるずる後ろに下がっていきそう。(追記:めでたく3.3に降格されました!) 元々非同期リセットいらないと言ってた人達らしいので、やる気が低いのでしょうね………。ただ、実装するとは約束しているようです。

 一応、回避策はあって、BlackBoxを使うという手段もあるけど、BlackBoxを使うと今度はFIRRTLのシミュレーションが出来ないでしょうね。


 なお、非同期リセットはないのに、マルチクロックドメインには対応しているという不思議。


 ちなみに、非同期リセットの日本語記事がありました。この記事で最後の方でSpinal HDLというChiselインスパイア言語を知ったのでそっちもちらっと見てみました。

 サクッと読んだ感じ、Spnial HDLは良さそうな感じですが、やっぱ金がね。Chiselは金が動いてる感あって安心感あるもんね。

 ただ、JavaScriptを見てる限り、Alt系の言語は激動の歴史を辿る可能性があります。Chiselにオールインするよりも、色々見ておく方がいいとは思う。

 

IOポートをVerilogに変換した時の命名を指定出来ない

 全てがChiselで終わるなら、別にVerilogに変換した時にどういう命名になろうが、そこまで気にしないでいいです。
 でも、全てがChiselで済む訳じゃないですよね。ChiselからVerilogを呼び出すのはまだ良いのですが、ChiselをVerilogから呼び出すってことも当然ある訳で。

 例えば、以下の様なモジュールの入力ポートは、「in」という名前にせよ、という指令が来ていても、Chiselでは出来ないのです。

class A extends Module{
  val io =IO(new Bundle{
    val in = Input(new Bool) //これは「input  io_in」というポートになる
  })
}

 いや、一応出来るんですよ。こうすれば。

class A extends Module{
  val io =IO(new Bundle{})
  val in = IO(Input(new Bool)) //これは「input  in」というポートになる
}

 ただ、こうすると、Bundleは使えないし、Chiselのルール的にI/Oなのかよくわからんくなる。(io.~は入出力)

 だから、こんな機能付けて欲しいですよね。

io.in.setName("in")

 というのも、これ、Chisel2ではあったそうなのですが、Chisel3では消されました。
 で、やっぱ不満に思っている人が居るらしく、issueにありました。requestとして受け入れられて、今のところ3.2で実装予定(あくまで予定)のようです。 拒否されました。ラッパー使えと。え、そういう問題なの!?

github.com

 ただ、何をどう実装するつもりなのか、ノープランぽいって言うか、とりあえず全部3.2にしとけって感じなので、ほぼ確実に3.2では実装されないでしょう。 
 
 
 

エラーが超不親切

 ビックリするくらい不親切だと思うわ。C++のtemplateと良い勝負してる気がする。

 C++のエラーメッセージがだいぶ親切になってきたのは近年だから、まだまだ時間はかかりそうかなー。

MSYSでVerilatorシミュレーションが出来ない

 Verilatorは問題ないのですが、Chiselが吐き出すC++コードがUnixのシステム(sys/mmanとか)に依存しています。
 なので、VerilatorシミュレーションはMSYSでやるのは諦めました。うん、めんどうくさい。WSLでUbuntu使えばいいだけだし。

 でも、できればさ、MSYSで完結したかったなぁ。うん、超個人的なデメリットだけど。

 え、Cygwin?………やーだー……


 


 どうでしたでしょうか。
 正直、結構デメリットの非同期リセットが出来ないというのと、ポート名を変えられないという点が結構痛くて、部分的にしかプロジェクトでは使えないと思っています。
 が、逆に私が論外すぎるなぁと思ったのもこの二点ぐらいしかないので、3.2でどのぐらい改善してくるのか、楽しみにしております。


 というわけで、ようやく次回から、Chiselの使い方の説明に入っていこうかな。