ABC135

今回はE問題がかなり難しかった。F問題より難しく感じた。 Youtubeの解説放送を聞いて、やっとわかってきた。 自分用のメモなので、日本語が雑になっている。。 ABC #135 D - Digits Parade dp[i][j]をi桁目まで見た時に、あまりがjとなる場合の数として、求めていく。 ABC #135 E - Golf 事前に、X>=0,Y>=0にしておく 1) X+Yが奇数 かつ Kが偶数 -1を返す。 どうやっても奇数番地にはたどり着けない 2) X+Y>K n=ceil(X+Y/K)として、X+Y と nK の偶奇が異ればn++とする。余剰 nK-X-Y のために、冗長な経路を作る。 ここで、X=0 だと、序盤の移動において、マンハッタン距離が正しくないので、swap(X,Y)しておく(もちろん出力時には戻す)。 +(X,Y) | Y (0,0)+ - t | | t = (nK-X-Y)/2 |-----| X 3)X+Y<K 3-1) X+Yが偶数 n=2となる。それ以降の計算は、2) と同じ。 +(X,Y) | Y (0,0)+ - t | | t = (2K-X-Y)/2 |-----| X 3-2) X+Yが奇数( 1) の条件よりKも奇数) n=3になる。これは思いつかない。この場合のみ、X, Y両方向に冗長な経路を取る必要がある。 p +----+ (X,Y) | Y (0,0)+ - t | | t = K-X |-----|----| X p = (K+X-Y)/2 4) X+Y==K 一発で行ける。...

August 3, 2019

ABC EF問題を埋めた(続き)

前回の続き。Atcoder Beginner Contest #130 ~ #133を解いたので、まとめておく。 まだまだ解説なしでは解けない。。 ABC #130 F - Minimum Bounding Box dp[i][j]をi,j番目が部分共通文字列となるときの組み合わせ数とする。 更新式もメモ化しておくと高速に計算できる。 ABC #131 F - Must Be Rectangular! (x,y)座標を2部グラフとみなす。 グラフに置き換えて考えることでスムーズに解ける。 ABC #132 F - Small Products N/xが同じ値になるxを同じグループとみなして、グループごとに計算を進める。 DPを圧縮していくイメージ。 ABC #133 F - Colorful Tree 木構造の頂点間の距離はLCA(最小共通祖先)を使うことで求めることができる。 実装解説は蟻本にまとまっている。 あらかじめクエリを先読みしておき、必要な頂点と色を抽出しておく。 DFSしつつ必要な値を埋めていく。

July 15, 2019

ABC EF問題を埋めた

Atcoder Beginner Contest #116 ~ #129のCD問題をすべて解いた。 また、#126 ~ #129についてはEF問題が追加されているので、すべて解いた。 F問題は、解説PDF、解説Youtube、解説ブログを参考にした。 ABC #126 F - XOR Matching https://atcoder.jp/contests/abc126/submissions/5909511 M=3とすると、長さ2^(M+1)の数列は、{0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7}のような要素をもつ。 このとき、{<0,1,...,7からKを除いた昇順の数列> K <7,6,...,0>からKを除いた降順の数列 K}とすれば良い。 K以外の要素について:間にはKだけが残ることになるので、条件を満す Kについて:間には <7,6,...,0>からKを除いた降順の数列 が残る。XORをとるとKになるので条件を満たす。 ABC #127 F - Absolute Minima https://atcoder.jp/contests/abc127/submissions/5930963 中央値が最小値となる性質を利用する。中央値が2つあるときには、左側を採用する。 中央値は、小さいほうと大きいほうをそれぞれ優先度付きキューで管理すると便利。 解説動画では、同一のaを二度入れてキュー間で交換するテクニックを使っていたが、 ナイーブに一度だけ入れる方法でも問題ない。 キューが片方に偏らないように、整理する必要がある。 更新クエリのとき、aが最小値を取る区間のなかに含まれていれば、最小値の更新はない。 一方、含まれていなければ、最小値を取る区間のなかで、最も近い点との差分を、最小値に追加する。 ABC #128 F - Frog Jump https://atcoder.jp/contests/abc128/submissions/5921198 A、Bをそのまま扱うのではなく、C=A-B と k=何度戻りが発生するか という変数に置き換えて考える。 Cを固定すると、kが増えるにつれて、蓮を多く踏めるようになる。 同一の蓮を二度以上通るかどうかは、単純にsetで管理した。 ABC #129 F - Takahashi’s Basics in Education and Learning https://atcoder.jp/contests/abc129/submissions/5945816 難しかった。まず、等差数列の各要素が何桁なのかによって、分割する。たとえば、A=3、B=4であれば、3,7と11,15,19に分けて考える。分割後は、sum_i=0^(l-1) (A+Bi)*10^k^(l-i-1)を求めることになる。 A sum_i=0^(l-1) 10^k^iとB sum_i=0^(l-1) i*10^k^(l-i-1)にわけて、計算する。 どちらも漸化式に変換して解く(コード中のf,gに対応)。 解説動画を見るのがおすすめ。

June 16, 2019

Go言語による並行処理 読書メモ

O’REILLYの「Go言語による並行処理」を読んので、自分用にメモを残しておく。 また、折角なのでhttps://godoc.org/github.com/bobuhiro11/gostream に、本文のアイデアをもとに並行処理に便利な関数群をまとめた。 競合状態は二つ以上の操作を正しい順番で実行しなければいけない状況で、プログラムがその順番を保証していないときに発生する。 論的な正当性を目指すべきで、Sleep関数を挟むような方法では解決しない。 デッドロックが起きる必要条件は、Coffman条件として知られている。 筆者の意見では、ライブロックはデッドロックよりも発見がむずかしい。プログラムの外部からリソース使用率を観測しても検出できないから。 並行処理に関わる関数には、適切にコメントをつける。誰が並行処理を担っているか、どのような並行処理のプリミティブに対応しているか、誰が同期処理を担っているか、を記述する。関数シグネチャでは不十分。 並行性(concurrent)はコードの性質、並列性(parallel)は実行中のプログラムの性質を指す。 Tony hoare「Communicationg Sequence Process」をもとに、Go言語の並行処理プリミティブは設計された。 CSPのほかにも、伝統的なメモリアクセス同期のコードも書ける。syncパッケージ中にまとめられている。 ただ、Goプログラミングスタイルでは、高水準の技術を使うのが推奨されている。ある瞬間に、ただ一つのゴルーチンのみが特定のデータを扱うようにすべき。 メモリ共有のかわりに、チャネルによる通信を行うべき。 メモリサイズに応じて、生成可能なゴルーチン数を概算できる。本文中の例によると、RAM 8GBで数百万のゴルーチンを生成できる。 sync.WaitGroupのAddの呼び出しはできる限り監視対象のゴルーチンの直前に書くのが良い。 デッドロックを避けるために、Mutexを使う時はUnlockの呼び出しをdeferの中で行う。 RWMutexはMutexよりも高機能。書き込みのロックを取っているものがいなければ、複数の読み込みロックを取得できる。 バッファ付きチャネルは早すぎる最適化になりやすい。デッドロックが見えなくなってしまう。 チャネルの所有権のスコープは小さくする。 Goランタイムはcase文全体に対して疑似乱数による一様選択をしている。 空select文 select {}は永遠にブロックする。 情報をたった一つの並行プロセスからのみ得られることを確実にする考え方に、拘束がある。 // チャネルへの書き込みスコープは、関数内にレキシカルに拘束される。 func owner() <-chan int { c := make(chan int) go runc() { defer close(c) for i:=0; i<10; i++ { c <- i } } return c } システムにキューを導入するのは便利だが、早すぎる最適化になってしまう。キュー導入の利点は、ステージの実行時間が減ることはなく、ステージのブロック状態の時間が減ること。 キューでは、リトルの法則でスループットを予測できる。 contextを関数の第一引数として渡す。よく使われるデータへの参照の保管には使わない。 ハートビートは必ずしも必要ではない。長時間稼働させる場合には有用。

April 22, 2019

BGP in the Data Center 読書メモ

BGP in the Data Centerの前半部分を読んだので、気になったところをメモしておく。CLOSネットワークをどのように設計するか、BGPをどのように運用するかについて、実践的な内容が書かれていた。普段触っていない領域なので、勘違いもあると思う。 1. Introduction to Data Center Networks ローカルネットワーク内のサーバ間通信をEast-Westトラフィック、ローカルネットワークと外部のネットワークの間の通信をNorth-Southトラフィックと呼ぶ。 大量のケーブルを管理する必要があるので、巨大なネットワークの管理者は、それぞれ管理技術を持っている。Prescriptive Topology Manager(PTM)というOSSもある。 同一のスイッチで巨大なネットワークを構成しておくと、故障した場合でも、単純に取り替えるだけで復旧できる。日々の運用コストについて考えておくことが大事。 CLOSネットワークを外部と接続するために、Border PodあるいはBorder Leavesを配置する。データセンタ内で使われているルーティングプロトコルは外部とは分離しておく。もし、Border PodやBordor Leavesを配置できない場合には、すべてのSpinesを外部と接続させる(Spineの対称性を保つため)。 iBGPに比較し、eBGPは理解やデプロイが容易なので、eBGPを採用するのが良い。歴史的な観点から、eBGPのほうが完成度の高い実装が多い。 2. How BGP Has Been Adapted to the Data Center PublicなASNは使わないほうが良い。オペレータを混乱させてしまったり、万が一外部に漏れた時にBGPハイジャックになってしまったりといった危険性がある。 2バイトのASNを4バイトへ拡張すると、およそ95,000,000個のprivate ASNを利用できる。 単純にすべてのBGPスピーカにユニークなASNを割り当てると、Path Huntingに苦しむことになる。 あるPrefixへの到達性をもつノードがダウンしたときに、その情報が収束するまでに時間がかかってしまう。これは、BGPのベストパス選択の性質に起因する。 真に到達不可能なのか、それとも別の経路でもって到達できるのかの区別ができない。 密に接続したCLOSトポロジでは、顕著な問題となる。 Path Hunting問題への対応として、以下のASN割り当てモデルがある。ループを検出できるので、必要以上にメッセージを送らなくて済む。ただし、Route Summarizationができないことに注意する。 すべてのToRはユニークなASN LeafはPodごとにユニークなASN。Pod内では同一のASN Spineは共通のASN OSPFやIS-ISはBest path選択のメトリクスを1つだけ。一方、BGPではそれが8つある。 Wise Lip Lovers Apply oral medication Every Night. Wight, LOCAL PREFERENCE, Locally originated, ASPATH, ORIGIN, MED, eBGP over iBGP, NextHop IGP Cost これら8つが等しければ、Equal Costと考えられ、Multipath Selectionできる。 ASPATHの比較については、長さに加えて要素がすべて等しければ、Equal Costとみなされる。 例えば、同一のPrefixが異なるASから届いた時には、Multi Pathとはならない。 ただし、bestpath -as-path multipath-relaxの設定を行うと、ASPATH長のみで(内容には触れずに)比較するよう設定できる。 タイマ設定を変更することで、CLOSトポロジにおける収束を早くする必要がある。ふつうはプロバイダ向けを想定して、安定性を第一にデフォルトが設定されていることが多いので、適宜設定する。 Advertisement Interval:このInterval内に含まれるメッセージは統合されて、送り出される。eBGPの場合、デフォルト30秒だが、0秒に設定すれば良い。 Keepalive and hold Timers:ある周期でkeepaliveメッセージをピアと交換する。Hold timeの期間内に、keepaliveを受け取らなかった場合は、ノードダウンと判定される。ケーブル障害の検知のために、BFD(Bidirectional forwarding Detectiion)を導入している場合でも、BGPプロセス自体のエラー検出のために、これらのタイマを調整する必要がある。おすすめは、3秒ごとのKeepaliveと9秒間のhold timersである。 Connect Timer:ピアの接続が切れた時、再接続までの待ち時間。 3....

March 21, 2019

東京マラソン2019

京都マラソンから、2週間が経過し、2019.3.3(日)東京マラソンに参加した。 こちらも初応募で初参加となった。 スタート前からゴール後まで、雨が振り続いていた。 特に、スタート前に30分以上、屋根のない中、待っているのがつらかった。 後半は、半分くらい歩いていて、ペースはぐだぐだだったが、無事完走できてよかった。 これで、今冬のマラソン大会参加は一旦終わりにする。 次の東京マラソン参加がいつになるかわからないが、来年も応募しようかな。

March 4, 2019

京都マラソン2019

2019.2.17(日)、京都マラソン2019に参加した。 初応募で初参加となった。 各地点での通過時間をメモしておく。ハーフ以降の距離でも、長い距離を歩くことはなかった。 スポーツ羊羹、ゼリー、塩飴など補給できるものを多く持っていったので、スタミナ切れがなかったのだろう。 他のマラソン大会だと7時間制限が多い気がするが、 京都マラソンは6時間制限なのでちょっときびしい。 特に、前半はスタートで出遅れたり坂があったりと遅れがちだが、 関門の制限時間がきびしくため、ギリギリで通過していた。 2週間後に、東京マラソンを控えている。そっちも頑張りたい。

February 20, 2019

ABC CD問題を埋めた

Atcoder Beginner Contest #1 ~ #115 の CD 問題をすべて解いた。 C問題は7割くらい、D問題は半分くらい自分の力で解くことができた。 特殊なアルゴリズムを使うことはあまりなく、ちゃんと考察できれば、解けるんじゃないかなと思う。 役立ちそうなことを残しておく。 Example の最初の1~2個は手で解いてみる。特に、幾何の問題は実際に書いてみる。 複数のパラメータを総当たりするときはどちらか一方のパラメータを固定して考える。 あらかじめソートや累積和を計算しておく。 その他、Youtube の解説動画が充実していて、かなり助けになった。

January 18, 2019

x86エミュレータ開発記録 (5)

あけましておめでとうございます。 x86のエミュレータの開発を続けてきましたが、半年が経過し開発速度もゆっくりになってきたので、 一旦このタイミングでコードを公開することにします。 https://github.com/bobuhiro11/tiny_x86_emu に置いているので、 興味があれば見てみてください。

January 4, 2019

x86エミュレータ開発記録 (4)

先月、Go 1.11がリリースされ、WebAssemblyが実験的にサポートされるようになった。 開発中のエミュレータもGoで書かれているということで、せっかくなので、 WebAssemblyに移植した。 単純にGoをWebAssemblyにコンパイルすると標準出力としてブラウザのコンソールが使われるが、 divタグの中に出力したかったので、syscall/jsパッケージでDOMを操作した。 その他の部分は特に変更の必要がなかった。 https://bobuhiro11.net/tiny_x86_emu/に公開している。 まだ開発途中という状態で、ユーザプロセス実行に関する開発が滞っているので、そろそろ手をつけていきたい。

September 19, 2018

x86エミュレータ開発記録 (3)

mpmain()、scheduler()、swtch()とプロセス切り替えできるまで、 エミュレータの開発が進んだ。 xv6のコードproc.cの334行目sti命令をずっと発行していて、どうやらループに入っているようなので、 ここでスケジューリング、コンテキストスイッチ周りをまとめたい。 切り替え先のプロセスは、切り替えられた直後forkret()、iinit()関数内にて、IOを行っている。 ここで、スリープ状態に入り、割り込みを待っているようだ。 proc構造体 xv6では各プロセスはproc構造体で管理される。 contextには、コンテキストスイッチのためのレジスタを格納する。 CSなどセグメントレジスタは、プロセス間で共通なので、保存する必要がない。 EAX、ECS、EDXなどは関数呼び出し時に自動的にスタックに保存されるため、contextに含めない。 最初のユーザプロセスは、userinit関数とallocproc関数で作成する。 proc構造体のコメントには、最初のユーザプロセスのデータをメモしておく。 トラップフレームは、ハードウェアとtrapasm.Sによりスタック上に積まれるもので、 trap関数へと引き渡される。 forkret関数のreturn先は、trapretに設定する。 struct proc { uint sz; // Size of process memory (bytes) pde_t* pgdir; // Page table char *kstack; // このプロセスのカーネルスタックの底 enum procstate state; // プロセスの状態:EMBRYO int pid; // PID:1 struct proc *parent; // 親プロセス:NULL struct trapframe *tf; // トラップフレーム struct context *context; // このプロセスのコンテキスト void *chan; // If non-zero, sleeping on chan int killed; // If non-zero, have been killed struct file *ofile[NOFILE]; // Open files struct inode *cwd; // カレントディレクトリ:/ char name[16]; // プロセス名:initcode }; struct context { uint edi; uint esi; uint ebx; uint ebp; uint eip; // forkret }; struct trapframe { // registers as pushed by pusha uint edi, esi, ebp, oesp, ebx, edx, ecx, eax; // rest of trap frame ushort gs, padding1, fs, padding2, es, padding3, ds, padding4; uint trapno; // below here defined by x86 hardware uint err; uint eip; ushort cs; ushort padding5; uint eflags; // below here only when crossing rings, such as from user to kernel uint esp; ushort ss; ushort padding6; }; struct { struct spinlock lock; struct proc proc[NPROC]; } ptable; カーネルスタック proc->kstackの中身を図示しておく。 swtchでは、espをproc->contextとして、edi、esi、ebx、ebpをpopする。 そして、最後にret命令で、eipを復元する。...

August 19, 2018

はじめて読む486の読書メモ

初めて読む486を読んだので、気になってことをメモしておく。 エミュレータを作っているので、参考になる。 全体を通して、図が分かりやすいので、図を見るだけでも勉強になる。 セグメント EIPから命令を読み出すときにはCSレジスタの指すセグメントが使われ、命令実行時のメモリアクセスにはDSレジスタの指すセグメントが使われる。また、PUSH、POP、CALL、RETなどスタックに関する操作には、SSレジスタの指すセグメントが使われる。スタックは下位アドレス方向に伸びるため、スタックセグメントのリミットは例外的に下限を指定する。 すべてのメモリアクセスのたびにセグメントディスクリプタを参照するのは、無駄が多いので、CPU内にセグメントディスクリプタ自体のキャッシュ(セグメントディスクリプタキャッシュ)を持つ。 プロテクトモードでは、CSレジスタが16ビットセグメントを指していれば、オペランドサイズとアドレスサイズは16ビットになる。同様に、32ビットセグメントでは、それらのサイズは32bitになる。 セグメントごとにDPL(Descriptor Privilege Level)で特権レベルを指定する。現在実行中のセグメントのDPLによって、CPL(Current Privilege Level)が決まる。CPLはCSレジスタの下位2bit、DPLはセグメントディスクリプタで設定される。ジャンプ先セグメントのDPLがCPLより高い場合には、直接ジャンプすることはできず、コールゲートを経由する必要がある。 ディスクリプタ GDTには、セグメントディスクリプタのほかに、TSS、コールゲート、タスクゲート、トラップゲート、割り込みゲートなど複数のシステムオブジェクトが格納される。 各種ゲートディスクリプタにもDPLを設定しておき、ゲートを呼び出すときに、CPLとDPLを比較する。CPLがゲートのDPL以上であれば、ゲートの先のセグメントのDPLによらず、そのセグメントにジャンプできる。 LDTを使うときは、GDT内にLDTを指すディスクリプタを作成して、そのセレクタ値をLDTRに設定する。 割り込み 割り込み番号は0x00~0xFFまで全256種類。 割り込みディスクリプタテーブル(IDT)には、ゲートディスクリプタを並べておく。割り込み番号がIDT内オフセットとなる。ゲートの種類は、割り込みゲート、トラップゲート、タスクゲートの3種類。 ふつうRET命令は単純にCS,EIPをPOPするだけだが、POPしたCSのDPLがCPLよりも低ければ、続けてSSとESPもPOPする。 低特権レベルからコールゲートを介してOSの関数を呼び出したとき、引数は低特権レベルのスタックにしか存在しないため、OSから簡単に扱えない。対策として、コールゲートのコピーカウントというパラメタに、引数のバイト数/4を設定しておき、自動的に引数をOS側のスタックにコピーさせる。戻るときは、オペランド付きRET命令を使い、OSのスタックをインクリメントさせる。 I/O IOポートはディスクリプタがないので、DPLを持たないが、代わりにIOポート専用の特権レベルIOPRL(I/O Privilege Level)がある。IOPRLは、EFLAGSレジスタで設定される。また、TSS内のIO許可マップで制御することもできる。 その他 クロックダブラーと呼ばれるクロック周波数を2倍にする技術があった。486DX2やODP(Over Drive Processor)で使われていた。 OSが利用するシステムレジスタはGDTR、IDTR、LDTR、TR、CR0~CR3。 DR0~DR7を操作することでブレークポイントを仕掛けて、デバッグできる。 アドレスバスとデータバスは32ビット、IOアドレスバスは16ビット。 オペランドサイズとアドレスサイズはそれぞれ32ビットあるいは16ビットで解釈される。どちらもプレフィックス(0x66あるいは0x67)をつけることでサイズを変更できる。 現在のタスクが使っているTSSのセレクト値は、TR(Task Register)に保持する。 同特権レベルでのCALL命令であれば、CSとEIPをPUSHして、ジャンプするだけ。異なる特権レベルへ移るためのコールゲートへのCALL命令であれば、スタックを切り替えてから、SS、ESP、CS、EIPをPUSHする。

August 4, 2018

x86エミュレータ開発記録 (2)

xv6のページングについてまとめておきたい。 カーネルmain関数では、ページテーブルやページディレクトリの初期化が2度行われる。 1度目のページング機構の初期化は、 仮想アドレスの下位4MB 0x0 ~ 0x400000 をそのまま物理アドレス 0x0 ~ 0x400000 にマッピングする。 また、0x80000000をオフセットとした仮想アドレス 0x80000000 ~ 0x80400000 についても、 同じく物理アドレス 0x0 ~ 0x400000 にマッピングする。 このページングはカーネル初期化時にのみ利用される。 CR4のPage Size Extension(4bit目)を有効にすることで、 ページサイズを4MBに拡張している(スーパーページ)。 スーパーページでは、ページテーブルは利用せずページディレクトリだけを使う。 仮想アドレスの上位10ビットがページディレクトリのインデックス、 下位10ビットが4MBページ内のオフセットに対応する。 つまり、1段のページング。 kinit1関数では、カーネルの終端から4MB(0x801154a8 ~ 0x80400000)のページに対してkfreeを実行し、 freelist(空きメモリをつなげたlinked list)に繋いでいく。 続いて、2度目の初期化では、 4MBを超える仮想アドレスを対象としている。 こちらは、スーパーページは使わないので、ページサイズは4KBのままで、 ページディレクトリとページテーブルのどちらも使う。つまり、2段のページング。 kinit2関数で、0x80400000 ~ 0x8e000000のページをfreelistに繋ぐ。 今回は、2度目の初期化のところでバグがあったため、 kinit2内で不正なアドレスに書き込みを行っていた。 2段のページング機構でのページウォークを見直して、解決した。 CR3の上位20bitがページディレクトリのベース物理アドレスを指しているが、 そのアドレスはCR3 >> 20ではなくCR3 & 0xFFFFF000であることに注意する。 ページディレクトリエントリについても同様のことが言える。 つまり、ページディレクトリやページテーブルは4KBでアライメントされている。

July 21, 2018

x86エミュレータ開発記録 (1)

自作エミュレータで学ぶx86アーキテクチャ という本を読んだ。 その続きとして、主に教育向けに使われているx86 OSのxv6を完動させることを目標に、 自作エミュレータを拡張していこうと思う。 比較的長期間にわたって開発することになるので、一旦今の状況をまとめておきたい。 現状では、ブートローダによってカーネル本体をメモリ上に展開し、 カーネルのmain関数から実行を開始できる状態になっている。 より正確には、ブートローダからカーネルのmain関数へと進み、 どこかの地点でカーネルパニックが起きている状態である。 また、シリアルポート(I/O Port 0x3F8)のエミュレートをできるようになっているので、 カーネルから cprintf 関数や panic 関数を呼び出すことで、任意の文字列を出力できる。 このあたりまでくるとCPU自体のエミュレートは落ち着いてきて、 各種IOや割り込みの実装が中心になってきていると感じる。 ある程度までまとまったら、コードを公開したい。 拡張にあたって、まずは本のコードの写経から始めた。 足りない命令については、インテルの仕様書を参考に随時追加していった。 Mod R/MやSIBバイトの動作については、手当たり次第に実装していたが、 インテルの仕様書を見れば一発でわかる話だった。 例外的な動作が多く、例えば、SIBバイトによるアドレス指定で Base=5 としたときには、 レジスタでなく disp8 や disp32 を使うことになる。 開発初期は各命令の動作を検証するために、QEMUの動作を正として、以下のようにQEMUのレジスタをトレースするGDBスクリプトを用意した。 10万ステップにわたり、自作エミュレータとQEMUのレジスタが一致するかどうかテストしながら、開発を進めた。 target remote localhost:1234 set architecture i8086 set confirm off break *0x7c00 c set variable $i = <numstep> while $i > 0 si info registers set variable $i -= 1 end quit xv6の動作についても、簡単にまとめておく。 xv6のイメージを指定し自作エミュレータを起動すると、 16bitモードで起動し、EIP=0x7c00 の状態からbootasm....

July 1, 2018

Chef実践入門の読書メモ

Chefを利用する機会があり、体系的に知りたいと持って、Chef実践入門を読んだ。 自分用に、そのメモを残しておく。 概要 管理サーバを介するかどうかによって、2種類の動作形態がある。1つ目は、管理サーバとしてChef Serverを介するサーバクライアントモデル。ローカル端末と、管理対象ノードの他に、Chef Serverを必要とする。ローカル端末・Chef Server間、Chef Server・ノード(Chef Client)間でやり取りする。ノード数の増加に強い。2つ目は、Chef Soloを使ったスタンドアロンモデル。Chef ServerもChef Clientも不要。小規模な環境で使われることが多い。いずれもRubyで実装されているので、gem install chef knife-solo berkshelfのように、gemによってインストールできる。 リポジトリ(キッチン)、クックブック、レシピという階層構造を持つ。リポジトリは、Gitなどでバージョン管理をする。site-cookbooksに自作のクックブック、cookbooksに外部クックブック、data_bagsにリポジトリ全体でグローバルなスコープのデータ、environmentsにdev/prodなどの環境情報、nodesにノードごとの設定情報(nodeオブジェクト)を配置する。また、Berksfileに依存する外部クックブック一覧を記述する。 クックブックの実装 同一構成の複数ノードを管理する場合には、ノードをまとめたroleを定義する。<repository>/roles/<role name>.jsonを作り、run_listなどを書いていく。また、Attributesを上書きすることもできる。default_attributesは定義されていないものを定義し、override_attributesは強制的に上書きするもの。 Attributeというkey-valueを管理する仕組みがある。自分で設定したり、システムから自動抽出することができる。自動抽出する場合には、ohaiコマンドの結果が使われる。慣習的に、ohaiで取得したの値のキーに関してはnode[:platform]のようにシンボルを利用し、Nodeオブジェクトで定義したキーに関しては、node["httpd"]["port"]のように文字列を利用する。Attributeは、<cookbook name>/attributes/defaults.rbにデフォルト値を定義できる。Attributeの優先順は、Nodeオブジェクト>ロール>Environment>レシピのAttribute>クックブックのAttribute。 cookbook_fileリソースは<cookbook name>/files以下のファイルを転送し、fileリソースはファイルを新規作成するために使われる。 ifconfig、mount、gem_package、git、http_request、route、ruby_blockリソースなどがある。もし、これらのリソースを使っても管理できないものがあれば、scriptリソースを使う。ただ、not_if、only_ifなどをうまく使って、冪等性を自分で保証する必要がある。 設定ファイルの配置後に、notifies :reload, "service[httpd]"のようにして、サービスのリロードできる。あるいは、subscribes :reload "template[/etc/httpd.conf]"によって、逆方向で定義できる。どちらも動作は同じで、キューに詰め込まれてまとめて実行される。 if文でインデントが深くなり可読性が下がってしまう場合には、only_ifなどの条件付きアクションを使うと良い。 レシピに書かれたリソースはコンパイル後に収束のタイミングで実行されるが、その他のRubyコードはコンパイル時に実行される。収束のタイミングで実行されるRubyコードを書きたければ、ruby_blockリソースを使う。 一連のリソースや処理は、Definitionとして、マクロのように実装できる。 Chef Solo Cookbookを開発するサーバと、管理対象ノードが同一の場合には、knife cookbook create <cookbook name>によりクックブックを作成し、chef-solo -o <cookbook name>によりクックブックを実行する。こういう使い方はあまりしないのかな。 開発サーバと管理対象ノードが異なる場合には、開発サーバでknife-soloを使う。knife-soloコマンドは、手元のクックブックをノードへ転送し、chef-soloを実行する。まず、開発サーバで、knife solo init .により、リポジトリを準備する。次に、knife solo prepare <hostname>により、管理対象ノードにche-soloをインストールする。続いて、knife cookbook create <cookbook name> -o <repository>/site-cookbooksで、クックブックを作成する。その後、クックブックを編集して、<repository>/nodes/<hostname>.jsonの中で{'run_list': ["recipe[<cookbook name>:<recipe name>]"]}と記述する。<recipe name>を省略すると、default.rbが参照される。最後に、knife solo cook <hostname>で、ノードをプロビジョニングする。なお、knife solo prepare <hostname>とknife solo cook <hostname>をまとめたknife solo bootstrap <hostname>コマンドもある。また、chef-soloにのみ依存するものはknife soloを使い、それ以外のものはknifeを使う。 その他 Test Kitchenを使って、クックブックを統合テストできる。Vagrantなどで、複数のOSを立ち上げる。テストの実行は、クックブックの適用後に、surverspecによって行われる。実際にテストを適用せずに、振る舞いをテストしたければ、ChefSpecを利用する。 knife cookbook site search <cookbook name>で外部のクックブックを検索して、Berksfileにcookbook '<cookbook>'追加する。その後、berksコマンドで、cookbooksディレクトリにダウンロード、展開される。 Opscode、Basecamp、RiotGames、aws、engineyard、pivotal-sproutなどがコミュニティクックブックを公開している。 Chef Serverは、新規clientの登録時に双方のvalidation....

October 21, 2017

Github PagesとCloudflareで静的サイトを配信

これまで、bobuhiro11.net と blog.bobuhiro11.net は、 自分で管理するサーバから配信していた。 ただ、どちらも静的サイトなので、必ずしも自分でインフラを管理する必要はなく、 楽をするために、これからはGithub Pagesを使って配信することにした。 調べてみたところ、Github Pagesでは、独自ドメインは利用できるが、HTTPSで配信することができない。 そこで、Github Pagesの前段に、SSL終端のできるCDNを配置した。 SSL終端のできるCDNは、いくつかあるようだが、 今回は無料で利用できるCloudflareを選択した。 Cloudflareには、DNSの機能もあるので、 お名前.comで登録している bobuhiro11.net とそのサブドメインを Cloudflareへ移行した。 まとめると、以下のようになる。 お名前.com:ドメインのレジストリ Cloudflare:DNSとCDN(SSL終端) Github Pages:静的サイトのビルドとHTTP配信 Githubの設定 2つのPrivateリポジトリを作成して、jekyllのコードをpush リポジトリの公開範囲がprivateであっても、gh-pagesブランチの内容は自動的に公開 リポジトリ直下に、ドメイン名を記述したCNAMEを配置 SettingsタブのGithub Pagesで確認 jekyllコードは自動でビルド Cloudflareの設定 ふつうzone apexにCNAMEレコードはマッピングできないが、 Cloudflareでは、CNAME Flatteningによって、例外的に割り当てることができる。 Aレコードよりも管理が楽なので、zone apexにもCNAMEを割り当てた。 適当にアカウントを登録して、設定を入れていく。 CloudflareとGithub Pagesの間では、sslを利用できないので、CryptoタブのSSL設定はFlexibleとした。 また、ブラウザにhttps接続を強制するために、HSTS(HTTP Strict Transport Security)の設定をする。 DNSタブ Type:CNAME, Name:blog, Value:bobuhiro11.github.io, TTL: Automatic, Status: DNS and HTTP proxy(CDN) Type:CNAME, Name:bobuhiro11.net, Value:bobuhiro11.github.io, TTL: Automatic, Status: DNS and HTTP proxy(CDN) Type:MX, Name:bobuhiro11.net, Value:xxxx, TTL: Automatic Type:TXT, Name:bobuhiro11....

October 7, 2017

GithubやBitbucketのプライベートリポジトリでCI/CD

GithubやBitbucketで管理している プライベートリポジトリに対して、 CI(継続的インテグレーション) とCD(継続的デリバリー)を実現する。 ここでは、werckerを使って、 テストとデプロイを自動化する方法をメモしておく。 werckerは、GithubとBitbucketどちらのプライベートリポジトリにも対応しており、 今のところ無料で利用できる。 デプロイ先はherokuとした。 herokuは、基本的に無料で、手軽にPaaS環境を利用できる。 ただし、無料枠での利用においては、 30分間アクセスがないとスリープ状態になったり、 稼働時間を月1,000時間に制限されたりするので注意する。 想定するアプリケーションは、Python3とFlask(Python向けウェブアプリケーションフレームワーク)で実装されたウェブサービスとする。 まず、リポジトリに3つの設定ファイル(wercker.yml、Procfile、runtime.txt)を追加する。 wercker.ymlは、werckerで利用する設定ファイルで、 大きく分けてbuildとdeployという2つのセクションから構成される。 buildセクションには、依存ライブラリのインストールと、ユニットテストの実行について記述する。 一方、deployセクションには、 herokuへのデプロイ時に参照するSSHキーペアの名前(key-name: HEROKU)を指定する。 HEROKUという名のSSHキーペアの作成手順は、後述する。 また、最新版のheroku CLIを利用するために、 install-toolbelt: true と記述しておく。 Procfileには、アプリケーション名: コマンドの記法で、起動コマンドを記述する。 さらに、runtime.txtでPythonのバージョンを指定する。 特に指定がなかった場合には、Python 2系がインストールされるので注意する。 # wercker.yml box: python services: build: steps: - script: name: install dependencies code: | pip3 install -r requirements.txt - script: name: test code: | python3 -m unittest discover -v && flake8 . deploy: steps: - heroku-deploy: install-toolbelt: true key-name: HEROKU # Procfile web: python -m web....

June 19, 2017

能登和倉万葉の里マラソン2017

2017.3.12(日)に,石川県七尾市で 開催された能登和倉万葉の里マラソン2017 に参加した. 初めてのフルマラソンだった. 高低差が多いのは難点だったが, 七尾西湾を一周するコースだったので, 漁港,山,海,橋など自然を満喫できた. さらに, 能登マ丼(牡蠣の入った丼)やおにぎりを頂いたり, 気温・天候がちょうど良かったりと終始気持ち良かった. 5km毎の通過時間とラップタイムを記録しておく. だんだんとペースが落ちていて,安定していない. 序盤から中盤にかけて11本の坂道があり, そこで調子に乗ってスピードを出しすぎたと思う. 20km地点で, 右足の足裏が痛みだしたが, 中敷きを外すと楽になったので走り続けた. その後,30km地点を過ぎたあたりから急に歩くのすら辛くなって, 休憩しつつ歩いた. 結果,順位は5,152人中3,096位. ちなみに,去年12月に参加したハーフマラソンでは, 1:47:54という結果だったので, なかなか単純計算ではいかないなという印象. 05km 00:36:55 10km 01:06:53 (29:58) 15km 01:38:46 (31:53) 20km 02:12:33 (33:47) 25km 02:55:19 (42:46) 30km 03:42:12 (46:53) 35km 04:32:00 (49:48) 40km 05:22:07 (50:07) ゴール 05:41:03 前日に18切符で会場周辺まで移動して前泊. マラソン後は,温泉に浸かり, サンダーバードで帰阪. またの機会があれば,後泊したい.

April 8, 2017

Go言語のメモ

「基礎からわかるGo言語」を読んだ. 2012年に発行された本なので,Goのバージョンがちょっと古い(Go 1.0.3)が,構文や考え方は大きく変わらないと思う. 今後,Go言語を使うことになるかもしれないので,気になったところをメモしておく. インスタンスの作成と初期化: インスタンスの作成方法には,下のコード例のように,いくつかの選択肢がある. 特に気を付けないといけないのは,Go言語にもポインタの概念があるので, ポインタと実体のどちらが生成されるのかという点である. また,インスタンス作成時に,構造体の要素に対する初期値を明示しなかった場合には, その要素にはゼロ値が割り当てられる点にも注意する. 例外として,スライス,チャネルおよびマップは参照型なので,newの代わりに,makeを使う. var x T // T型 y := T{ } // T型 z := &T{ } // *T型 w := new(T) // *T型 ブランクフィールド: 構造体の定義において,_ byteのように名前のない要素を定義すると,パディングを実現できる. インターフェースとnil: インターフェースに,T型の値xを代入すると,内部では<T,x>のように型と値が組になって格納される. これに起因して,インターフェース型の値pがnilかどうかをチェックするときは, 単純にnilと比較するのではなく,reflect.ValueOf(p).IsNil()を使う. var p1 *int var p2 interface{} = p1 fmt.Println(p1 == nil) // true fmt.Println(p2 == nil) // false fmt.Println(reflect.ValueOf(p2).IsNil()) // true リカバリ: 配列の範囲を超えたインデクス参照などによって致命的なエラーが発生したとき,あるいはpanic関数を呼び出したとき,プログラムはパニック状態になる. パニック状態になると,関数実行は中断され,main関数までコールスタックを遡っていく. ただし,その途中で,defer文によって遅延指定された関数は実行される. deferにより遅延して呼び出しされた関数の中で,そのパニックに対処できた場合は, recovery組み込み関数によって,パニックによるコールスタックの連鎖を中断できる. lenとcap: スライスsは,配列へのポインタ,長さlen,および容量capを持つ. ここで,スライスsの部分要素を参照するためにv := s[2:4]とすると, vとsは同じ配列を参照することになる. コピーが欲しければ,明示的に,copy関数を使わなければならない. この辺りは,内部構造を考慮しながら,コーディングしたほうが良い....

January 21, 2017

2016年総括

例年どおり今年一年を振り返ってみることにした. 研究生活,アルバイト,趣味などを,項目ごとに思い出してまとめておく. 今年で,学生生活が終わることになる. ただ,修論と論文誌が残っているので, 年が開けても忙しくなりそう. 来年4月からは,関東に引っ越すことになった. UFJ,宝塚,通天閣にまだ行ってないので,関西にいる間に一度は行っておきたいところ. 研究 今年は,2つの国際会議で発表をした. 1つ目は,ギリシャで開催された会議である. 具体的には,ギリシャ・クレタ島の北部に位置する街イラクリオンで開催されたPDP2016である. これは,研究室に所属してから,初めての海外発表だった. 自分の発表は,会議全体からみて後半のほうだったと思う. 15分くらい拙い英語で発表をした. ただ,時間の都合で質疑応答が省略されたため,ちゃんと伝わったかどうかわからない. 移動の合間にクノッソス遺跡,パルテノン神殿,アテネ国立考古学博物館,ゼウス神殿を観光して周った. 2つ目は,11月にソルトレイクシティで開催された会議SC16である. ワークショップで発表した. 今回は,質問やコメントが3件あったが,ちゃんと答えられなかった. 言いたいことがあっても,なかなか英語が出てこなかった. 観光の時間はあまりなかったが,街の中心部にあるテンプルスクエアでオルガンリサイタルを聴くことができた. 復路で,ソルトレイクシティ発ロサンゼルス行きの飛行機がエンジントラブルか何かで遅れてしまうトラブルがあった. 他には,松本市で開催されたSWoPP2016で発表した. 後輩と一緒に参加して,発表をした. さらに,先輩が表彰受賞のために参加していて,一緒に懇親会で話をした. 2/15-22 PDP2016@ギリシャ 8/8-11 SWoPP2016@松本 9/12-13 旅行@金沢 10/5 GPU Japan@東京 10/5-7 OpenMPCon,IWOMP@奈良 11/13-19 SC16@ソルトレイクシティ アルバイト 3年くらいお世話になっている梅田の会社で,引き続きアルバイトとして,仕事をしていた. 今年は,サービスそのものの開発の他に,周辺ツールの整備をしていた. まず,サムネイル画像などを配信するためのCDN(Contents Delivery Network)を構築した. Nginxとそのモジュールで画像処理を行い,Amazon CloudFrontで配信した. 次に,Elasticsearchで各種ログを収集する環境を整えた. Amazon RDS,PHP,Nginxなどのログを収集・検索できるようになった. 最後に,cronで管理していたジョブをRundeckで管理するよう置き換えた. ジョブの実行ログをAmazon S3に,プロジェクトの設定をAmazon RDSに,それぞれ格納することで, 冗長構成になっている. アイドル しゃちほこ,アプガを中心に,いくつかのライブに参戦した. しゃちほこメンバが髪色を変えてみたり,干され気味の曲をセトリに取り入れてみたり,と満足度が高かった. アプガは,初の武道館ライブをやった.最後の挨拶によると,どうやら2期メンバを募集するらしい. 1/3 アプガ@梅田 5/21-22 しゃちほこ@幕張 7/17 アプガ@天満 7/29 Edge Dub Monkeyz@難波 8/3 しゃちほこ@名古屋 9/10 しゃちほこ@長崎 9/11 しゃちほこ@福岡 10/28 しゃちほこ@難波 11/8 アプガ@東京 バイク ほぼ毎日乗っているので,徐々に不具合が出てきた. 順次,オイル,フィルター,タイヤ,バッテリ,スパークプラグ,チェーン,スプロケを交換した. 加えて,二輪用ETCを取り付けた....

December 31, 2016