年末の帰省チケットを解約したとき(2020年12月17日の日記参照)に価格が激変していたことが気になったので、年末年始の羽田→千歳便の各チケットの価格をプロットしてみました。
どうやらチケットの種類に関係なく、最後に付いているアルファベットで価格帯が決まるようです。Aが一番高くて、B, C, D, ... と安くなっていくようです。10月に予約したSUPER VALUE 75 Hが、今日予約できるVALUE 3 Jより高くなるのはこれが理由でした。
ANAの予約システムは、遠い予約日(1/Mくらい)だと、空席予測を強気に出すのかやや割高の運賃設定をしています。
くらいかな?早朝便、深夜便などは1ランク安くなりがちです。しかし、搭乗日が近づいて(増発を決めてしまった12/30など)、誰も乗らないことに気づき始めると、未だかつて見たことない安さのチケットが出現します。
こんな感じですね。安いなあ。
遠い予約日が強気の価格になるのは、SUPER VALUEでも傾向が一緒のようです。SUPER VALUEの予約日は最短でも21日後と、必然的に遠くなるため、COVID-19の状況下ですと、予約日が遠いSUPER VALUEの方がかえって割高で買ってしまう可能性が高いです。
例えば、一番近いSUPER VALUEの予約日は21日後の1/10です。ラインナップはVALUE 3 H, VALUE 1 G, SUPER VALUE 21 J辺りで、今この瞬間はSUPER VALUE 21 Jが一番安く見えますが、1/10はおそらく誰も乗りません(帰省ラッシュがない以上、Uターンラッシュも起きない)から、1/3くらいまで待てば、VALUE 3 Kとかが登場して、SUPER VALUE 21 Jの価格を下回ると思います。
しかも今は「あんしん変更キャンペーン」があるので、SUPER VALUE 21 Jで予約して払い込んでしまい、年始に安い便があれば切り替え、払い戻しを受ければノーリスクで安く乗れるはずです。
未だかつて年末の羽田→千歳便がこんな低価格で投げ売りされたことはありません。どれだけぼったくっても、皆が渋々乗るので「ドル箱路線」と称されたほどです。
10年来、散々、羽田→千歳便でボラれてきた身としては、今年は流石のANAもぼったくりはできなかったか……と思いました。けどまあCOVID-19に関しては同情しかなくて、乗れる機会があったら飛行機乗って応援したいですね。九州辺りに旅行に行きたいな〜。
「あんしん変更キャンペーン」はただでさえ客足が遠のく中、安く乗られ、割安で解約され、ANAとしては散々でしょう。
逆にこっちはあまり同情してません。飛行機の割引制度は縛りが多くて理不尽です。今の方が素直だし普通です。是非、このまま続けて欲しいですね。
メモ: 技術系?の話はFacebookから転記しておくことにした。いろいろ修正。
目次: 車
車に乗ってるとたまに疑問に思うんですが、燃費ってアクセル開度で決まるんですかね?
同じ勾配、同じアクセル開度なら、毎速2500rpmで変速しても、2速5000rpmまで引っ張って、すぐ3, 4, 5速と変速しても、燃料消費量は同じ??なんてことをFacebookに書いてみたところ、会社の同僚のみなさんから色々教えていただけました。
同じアクセル開度なら、エンジンの燃焼効率の最適点が一番燃費が良いので、1速でぶん回すより、4速くらいの方が一般的には燃費が良いはず、とのことです。レスが超早かったです。さすが車の専門家達の会社だなと痛感しますね。
通常、燃焼効率の最適点は公開されていません。代わりとしてエンジン出力の最大点を使おうと思います。燃焼効率最適点=燃費の最大点、エンジン出力の最大点=加速の最大点であり、この2つは一致しません。ただし、効率が悪いにも関わらず最大出力に達するのは、ちょっと考えにくいですし、一致はしなくてもさほど遠くないだろう、という目論見です。
スバルのEJ20エンジンはいろんな車種に乗っていて、自分のレガシィB4のエンジン性能曲線が探せませんでした……。インプレッサWRX STIのEJ20エンジン性能曲線はすぐに出てきた(パワーユニット : ドライビング - WRX STI - SUBARU)ので、これを参考にしようと思います。
もちろん
辺りはわかってます。
が、まあ、ざっくり言って、トルクカーブは2500〜4500rpmくらいまでピークかつ真っ平らです。ほぼどこで変速しても大丈夫!素晴らしいエンジンですね〜。
2000rpm前後の加速が眠くて、突然速くなる感じがするのも、レガシィが重たいからだと思いこんでいたんですけど、2000〜2500rpmでトルクが急激に立ち上がるエンジン特性からくるものなんですね。見覚えあるなと思って調べたら、昔も同じことを言っていました(2010年9月5日の日記、2010年9月7日の日記参照)。完全に忘れてました。
何年乗ってるんだ、今更かよって感想ですけど……。
Facebookで教えていただいたところによると、EJ20はOBD2端子(On-board diagnosticsという故障診断の信号を送受信できる端子)から燃料消費量の情報が取れるはずなので、それを見たらどうか?ELM327互換のアダプタでBluetoothでスマホにデータを送る手もある、という素晴らしいアイデアをいただきました。
昔に付けたメーター(2011年5月4日の日記参照)で、瞬間燃費が表示できないか試してみようかな。
メモ: 技術系?の話はFacebookから転記しておくことにした。大幅に追記。
実家と話し合って、今年末の北海道への帰省を取りやめました。年末がクッソ暇になりました。
帰省用の飛行機チケットを解約したんですが、ANAが最近やってる「あんしん変更キャンペーン」(ANA公式サイト)により、運賃や解約ルールが意味不明になってます。
買ったチケットは、
計95,040円です。
解約の仕方をいくつか試したところ、払戻金額の見積もりがべらぼうに変わり驚きました。
各パターンで何が起きているのでしょう?個人的な予想に過ぎませんが、
バリュー系チケットの値段は需要連動(ANAの解説)らしく、11月のコロナ再流行で需要が急激に落ち込み、スーパーバリュー75Hとバリュー3Jの逆転現象が発生したのでしょう。この需要連動という想定そのものが「直前に需要が急減する」という事態を想定していない節がありますね。
もし10月くらいにスーパーバリュー系を予約した人は、1万円単位で大損してるはずです。年末に飛行機に乗る人は要確認です。
今のANAの一番良くないところは、普通に解約すると5万円近く大損するところですが、ANAのQAを見る限り「コロナ関連で解約の特別対応はしない、所定のキャンセル料を払え」とあるのでANAとしてはパターン1の解約でANAに5万円寄付せよ、という意思なんでしょうか?
私は、パターン3を試してみたので、手数料含めて2,500円くらいで解約できちゃったように見えます。
予約システムのバグだったんですかね?ちゃんと払い戻しされるかなあ??不安だわあ……。
メモ: 技術系?の話はFacebookから転記しておくことにした。
目次: Zephyr
前半ではztest_test_suite() の実装を見ました。戻って見るのは面倒だと思うのでztestの使い方の例を再掲しておきます。
// zephyr/tests/lib/sprint/src/main.c
void test_main(void)
{
ztest_test_suite(test_sprintf, //★変数名★
ztest_unit_test(test_sprintf_double), //★テスト1つ目★
ztest_unit_test(test_sprintf_integer), //★テスト2つ目★
ztest_unit_test(test_vsprintf),
ztest_unit_test(test_vsnprintf),
ztest_unit_test(test_sprintf_string),
ztest_unit_test(test_sprintf_misc));
ztest_run_test_suite(test_sprintf);
}
後半のztest_run_test_suite() マクロの実装を見ます。
// zephyr/subsys/testsuite/ztest/include/ztest_test.h
/**
* @brief Run the specified test suite.
*
* @param suite Test suite to run.
*/
#define ztest_run_test_suite(suite) \
z_ztest_run_test_suite(#suite, _##suite)
// zephyr/subsys/testsuite/ztest/src/ztest.c
void z_ztest_run_test_suite(const char *name, struct unit_test *suite)
{
int fail = 0;
if (test_status < 0) {
return;
}
init_testing(); //★何もしない★
PRINT("Running test suite %s\n", name);
PRINT_LINE;
while (suite->test) {
fail += run_test(suite); //★テストを実行★
suite++;
if (fail && FAIL_FAST) {
break;
}
}
if (fail) {
TC_PRINT("Test suite %s failed.\n", name);
} else {
TC_PRINT("Test suite %s succeeded\n", name);
}
test_status = (test_status || fail) ? 1 : 0;
}
#ifndef KERNEL
...
#else
...
static int run_test(struct unit_test *test)
{
int ret = TC_PASS;
TC_START(test->name);
//★テスト関数1つに対し、1つスレッドを作る★
k_thread_create(&ztest_thread, ztest_thread_stack,
K_THREAD_STACK_SIZEOF(ztest_thread_stack),
(k_thread_entry_t) test_cb, (struct unit_test *)test,
NULL, NULL, CONFIG_ZTEST_THREAD_PRIORITY,
test->thread_options | K_INHERIT_PERMS,
K_NO_WAIT);
k_thread_name_set(&ztest_thread, "ztest_thread");
k_thread_join(&ztest_thread, K_FOREVER);
phase = TEST_PHASE_TEARDOWN;
test->teardown();
phase = TEST_PHASE_FRAMEWORK;
...
#endif /* !KERNEL */
関数run_test() は非常に特徴的で、ztestでは各ユニットテストを実行する際に、専用のスレッドを生成する仕組みになっています。浮動小数点数命令がIllegal Instruction例外になってしまうのは、この仕組みが原因です。
勘の良い人はZephyrのドキュメント(k_thread_create() へのリンク)を見ただけで、何が悪いかわかるかも。
手掛かりはAPIのoptions引数がtest->thread_options | K_INHERIT_PERMSになっていることです。前半で説明したとおりtest->thread_options = 0であり、K_INHERIT_PERMS以外のオプションは指定されません。スレッド内で浮動小数点数命令を使いたいならK_FP_REGSの指定が要るのでは?と思った方、その通りです。大正解。
K_FP_REGSが答えですよと言われても、何だそれ?と思うほうが普通です(私もそうでした)。Zephyrのスレッド生成関数をざっと追いかけましょう。
// (build_dir)/zephyr/include/generated/syscalls/kernel.h
static inline k_tid_t k_thread_create(struct k_thread * new_thread, k_thread_stack_t * stack, size_t stack_size, k_thread_entry_t entry, void * p1, void * p2, void * p3, int prio, uint32_t options, k_timeout_t delay)
{
#ifdef CONFIG_USERSPACE
if (z_syscall_trap()) {
uintptr_t more[] = {
*(uintptr_t *)&p2,
*(uintptr_t *)&p3,
*(uintptr_t *)&prio,
*(uintptr_t *)&options,
*(uintptr_t *)&delay
};
return (k_tid_t) arch_syscall_invoke6(*(uintptr_t *)&new_thread, *(uintptr_t *)&stack, *(uintptr_t *)&stack_size, *(uintptr_t *)&entry, *(uintptr_t *)&p1, (uintptr_t) &more, K_SYSCALL_K_THREAD_CREATE);
}
#endif
compiler_barrier();
//★今回、ユーザー空間は未使用なので、引数を同じ順で渡すだけ★
return z_impl_k_thread_create(new_thread, stack, stack_size, entry, p1, p2, p3, prio, options, delay);
}
// zephyr/kernel/thread.c
#ifdef CONFIG_MULTITHREADING
k_tid_t z_impl_k_thread_create(struct k_thread *new_thread,
k_thread_stack_t *stack,
size_t stack_size, k_thread_entry_t entry,
void *p1, void *p2, void *p3,
int prio, uint32_t options, k_timeout_t delay)
{
__ASSERT(!arch_is_in_isr(), "Threads may not be created in ISRs");
/* Special case, only for unit tests */
#if defined(CONFIG_TEST) && defined(CONFIG_ARCH_HAS_USERSPACE) && !defined(CONFIG_USERSPACE)
__ASSERT((options & K_USER) == 0,
"Platform is capable of user mode, and test thread created with K_USER option,"
" but neither CONFIG_TEST_USERSPACE nor CONFIG_USERSPACE is set\n");
#endif
z_setup_new_thread(new_thread, stack, stack_size, entry, p1, p2, p3,
prio, options, NULL); //★スレッドの情報初期化★
if (!K_TIMEOUT_EQ(delay, K_FOREVER)) {
schedule_new_thread(new_thread, delay);
}
return new_thread;
}
ここまでは入り口です。ユーザー空間を使わない限り、多少チェックが入っているくらいで、ほぼ素通りします。
/*
* The provided stack_size value is presumed to be either the result of
* K_THREAD_STACK_SIZEOF(stack), or the size value passed to the instance
* of K_THREAD_STACK_DEFINE() which defined 'stack'.
*/
char *z_setup_new_thread(struct k_thread *new_thread,
k_thread_stack_t *stack, size_t stack_size,
k_thread_entry_t entry,
void *p1, void *p2, void *p3,
int prio, uint32_t options, const char *name)
{
char *stack_ptr;
...
z_waitq_init(&new_thread->base.join_waiters);
/* Initialize various struct k_thread members */
z_init_thread_base(&new_thread->base, prio, _THREAD_PRESTART, options); //★スレッド生成(共通部分)★
stack_ptr = setup_thread_stack(new_thread, stack, stack_size);
#ifdef KERNEL_COHERENCE
/* Check that the thread object is safe, but that the stack is
* still cached!
*/
__ASSERT_NO_MSG(arch_mem_coherent(new_thread));
__ASSERT_NO_MSG(!arch_mem_coherent(stack));
#endif
arch_new_thread(new_thread, stack, stack_ptr, entry, p1, p2, p3); //★スレッドの生成(アーキテクチャ依存の処理)★
/* static threads overwrite it afterwards with real value */
new_thread->init_data = NULL;
new_thread->fn_abort = NULL;
#ifdef CONFIG_USE_SWITCH
/* switch_handle must be non-null except when inside z_swap()
* for synchronization reasons. Historically some notional
* USE_SWITCH architectures have actually ignored the field
*/
__ASSERT(new_thread->switch_handle != NULL,
"arch layer failed to initialize switch_handle");
#endif
...
void z_init_thread_base(struct _thread_base *thread_base, int priority,
uint32_t initial_state, unsigned int options)
{
/* k_q_node is initialized upon first insertion in a list */
thread_base->user_options = (uint8_t)options; //★オプションはtest->thread_options (= 0) | K_INHERIT_PERMS (= 8) ★
thread_base->thread_state = (uint8_t)initial_state;
thread_base->prio = priority;
thread_base->sched_locked = 0U;
#ifdef CONFIG_SMP
thread_base->is_idle = 0;
#endif
/* swap_data does not need to be initialized */
z_init_thread_timeout(thread_base);
}
// zephyr/arch/riscv/core/thread.c
void arch_new_thread(struct k_thread *thread, k_thread_stack_t *stack,
char *stack_ptr, k_thread_entry_t entry,
void *p1, void *p2, void *p3)
{
struct __esf *stack_init;
...
#if defined(CONFIG_FPU) && defined(CONFIG_FPU_SHARING)
if ((thread->base.user_options & K_FP_REGS) != 0) { //★この条件に引っかからず、浮動小数点数演算機能が有効にならない★
stack_init->mstatus |= MSTATUS_FS_INIT;
}
stack_init->fp_state = 0;
#endif
stack_init->mepc = (ulong_t)z_thread_entry_wrapper;
...
アーキテクチャ依存処理arch_new_thread() にやっとK_FP_REGSが出現します。user_optionsはz_init_thread_base() で設定しているとおり、APIの引数optionsの値そのものです。
引数optionsにK_FP_REGSを指定しない場合、mstatus CSRのFSフィールドが設定されず0のままになります。RISC-Vの仕様では、ハードウェアが浮動小数点数命令をサポートしていても、mstatusのFSフィールドが0だとIllegal Instruction例外を発生させます。QEMUも当然この仕様に習った実装になっています(2020年12月10日の日記参照)。
以上がztestで浮動小数点数命令を使うと例外が発生する原因です。原因はわかりましたが、スマートな直し方がわからないので、修正に関しては保留中です。
最初の方でinit_testing(); //★何もしない★ とだけ書いてスルーしてしまった部分がありましたので、実装を載せておきます。
// zephyr/subsys/testsuite/ztest/src/ztest.c
#ifndef KERNEL
...
#else
...
static void init_testing(void)
{
k_object_access_all_grant(&ztest_thread);
}
#endif /* !KERNEL */
// zephyr/(build_dir)/zephyr/misc/generated/syscalls_links/include/sys/kobject.h
static inline void k_object_access_all_grant(const void *object)
{
ARG_UNUSED(object);
}
この通り、何もしていません。
< | 2020 | > | ||||
<< | < | 12 | > | >> | ||
日 | 月 | 火 | 水 | 木 | 金 | 土 |
- | - | 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 | - | - |
合計:
本日:
管理者: Katsuhiro Suzuki(katsuhiro( a t )katsuster.net)
This is Simple Diary 1.0
Copyright(C) Katsuhiro Suzuki 2006-2023.
Powered by PHP 8.2.18.
using GD 2.3.3(png support.)