Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

voicevox engineが異常終了する #384

Closed
1 of 3 tasks
anyworks opened this issue Mar 31, 2022 · 8 comments · Fixed by #424
Closed
1 of 3 tasks

voicevox engineが異常終了する #384

anyworks opened this issue Mar 31, 2022 · 8 comments · Fixed by #424
Labels
OS 依存:win Windows に依存した現象

Comments

@anyworks
Copy link

不具合の内容

voicevox engineが異常終了する

現象・ログ

voicevox_engine_1 | WARNING: JPCommonLabel_insert_word() in jpcommon_label.c: First mora should not be short pause.
voicevox_engine_1 | *** stack smashing detected ***: terminated
docker_voicevox_engine_1 exited with code 139

再現手順

voicevox-engineのaudio_queryAPIのパラメータ"text"に値として、JSON文字列を与える
例)/audio_query?speaker=1&text=${JSON_STRING}

audio_queryが出力したJSONを誤って指定したら発生しました。(2回中2回再現)

期待動作

変換処理のエラー判別がなんらかの方法で可能

VOICEVOXのバージョン

0.11.4

OSの種類/ディストリ/バージョン

  • Windows
  • macOS
  • Linux

Windows 10 Pro 64bit (19044.1586)

その他

楽しく使わせてもらってます。ありがとうございます。
環境としては、Windows10 上でのdocker環境起動です。
#377の方が言っている、std::bad_allocエラーにも出くわしましたが、今回のエラーはその原因とは関係無いようです。参考まで。

@github-actions github-actions bot added the OS 依存:win Windows に依存した現象 label Mar 31, 2022
@takana-v
Copy link
Member

長すぎる文字列が渡されたせいでクラッシュしたと思われます。
原因はここら辺だと思います。

https://github.com/VOICEVOX/pyopenjtalk/blob/a85521a0a0f298f08d9e9b24987b3c77eb4aaff5/pyopenjtalk/openjtalk.pyx#L167

この2つの関数の引数であるtextの長さが一定以上だった場合、エラーを返すようにすると改善すると思います。
https://github.com/VOICEVOX/pyopenjtalk/blob/a85521a0a0f298f08d9e9b24987b3c77eb4aaff5/pyopenjtalk/__init__.py#L85
https://github.com/VOICEVOX/pyopenjtalk/blob/a85521a0a0f298f08d9e9b24987b3c77eb4aaff5/pyopenjtalk/__init__.py#L160

# 値は適当です
if len(text) > 200:
    raise ValueError("入力の文字列が長すぎます。")

こうすることでaudio_queryAPIのパラメータtextに値として、JSON文字列(長い文字列)を与えた場合には500エラー(Internal Server Error)が返ってくるようになります。
できればエディタによるエンジン再起動を防ぐため400番台のエラーを返すようにしたいですが、現在のエディタでは長い文字列を入力した場合に警告が出るようになっているので、とりあえず500エラーでもいいかと思います。

Cython周りはちょっと自信が無いため、他の方にも意見を伺いたいです。

@Hiroshiba
Copy link
Member

同じく、文章が長すぎることが原因なエラーかなと思いました。
もしそうであれば、メモリ使用量がぐんぐん上がっているはずです。
実行中のメモリ使用量を見てみていただいてもよろしいでしょうか・・・?👀 @anyworks

@anyworks
Copy link
Author

anyworks commented Apr 3, 2022

JSON自体は問題とされていないようなので、全角ひらがな3000文字のテキストを用いてテストした結果
興味深い挙動に遭遇しました。

1回目リクエスト結果ログ

voicevox_engine_1  | WARNING:  Invalid HTTP request received.
voicevox_engine_1  | Traceback (most recent call last):
voicevox_engine_1  |   File "/home/user/.local/lib/python3.8/site-packages/uvicorn/protocols/http/h11_impl.py", line 136, in handle_events
voicevox_engine_1  |     event = self.conn.next_event()
voicevox_engine_1  |   File "/home/user/.local/lib/python3.8/site-packages/h11/_connection.py", line 432, in next_event
voicevox_engine_1  |     raise RemoteProtocolError(
voicevox_engine_1  | h11._util.RemoteProtocolError: Receive buffer too long

実行後サーバ状態 => 稼動

2回目リクエスト結果ログ(同じテキスト)

voicevox_engine_1  | *** stack smashing detected ***: terminated

実行後サーバ状態 => 異常終了

ちなみに、メモリ使用量はこの時点では微々たるものでした。

ただ、このテスト中docker落ちる→docker再起動を繰り返しているうちに、voicevox-engineがメモリだけを永遠に食いつぶして起動しないという事象にも遭遇しました。(Vmmem.exeが延々とメモリ消費している状態になる)
結果、物理メモリが足りなくなり、プロセスは起動する事なく以下コードで終了しました。。(物理メモリは32GB)

voicevox_engine_1  | + exec gosu user /opt/python/bin/python3 ./run.py --use_gpu --voicelib_dir /opt/voicevox_core/ --runtime_dir /opt/onnxruntime/lib --host 0.0.0.0
voicevox_engine_1  | Warning: cpu_num_threads is set to 0. ( The library leaves the decision to the synthesis runtime )
docker_voicevox_engine_1 exited with code 137

@Hiroshiba
Copy link
Member

なるほどです!!

文字数が多くてメモリを食いつぶしてしまう感じなんですね!
なぜか1回目は異常終了しないとの調査もありがとうございます。

@takana-v さんの仰るように、メモリオーバーで異常終了しないように、文字数が多かったらエラーを返すというのはどうでしょう。

思いつく最長の日本語はじゅげむなのですが、どうやら140文字程度らしいです。
https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1313105563
それが3回くらい入る、500文字を超えたときにエラーを返す、とか。

@anyworks さん、プルリクエスト作成に挑戦してみませんか・・・?👀

@anyworks
Copy link
Author

anyworks commented Apr 4, 2022

気になったので、限界の閾値を調べてみました。
結果として、異常終了しない閾値は全角で2733文字でした。
全角で2733以内であれば、何回送っても異常終了することはなかったです。
この結果を受けて、これを文字列長設定の根拠としてひとまずは「2733」もしくは、意味がくみ取りやすい「2560」程度にする案でも良いかと考えます。
ただ、閾値は半角換算して5,466byteなんですが、あまり一般的でない数字なのでテストPGのバグかもしれませんので、一応テストに使ったスクリプトを添付しておきます。

test用powershellスクリプト

function makePhrase($len){
    $token = "隣の客は良く柿食う客だ"

    [int]$length = $len
    [int]$loop =  [Math]::Truncate($length / $token.Length)
    [int]$mod = $length % $token.Length

    $res=""
    for($i=0 ; $i -lt $loop;$i++){
      $res+= $token
    }
    $mod--
    if($mod -ne -1){
        $res += $token[0..$mod] -join ""
    }
    $res
}
#[OK]2733 [KO]2734
$basephrase = makePhrase(2733)  #一度に送る文字列サイズを指定

$i=2 #リクエストをvoicevoxのログで見分けたい場合、都度変える
$basephrase = $basephrase[0..($basephrase.Length-5)] -join ""
$num = (""+$i).padLeft(4,"0")     
$phrase = $basephrase + $num
write-host $phrase
write-host "length to send:" $phrase.Length
  
Invoke-WebRequest  -Uri  "192.168.10.11:50021/audio_query?speaker=1&text=$phrase" -Method "POST" | out-null
write-host "end request"

pythonにはあまり明るく無いのですが、自身が発行したIssueでもありますし
プルリク作成させて貰えるならチャレンジしてみたいと考えています。(文字列長チェック実装程度で済むのであれば。ですが。。)

@Yosshi999
Copy link
Contributor

utf-8ではその文字種で2733文字だと8199bytes (一文字3bytes)なので、上記( #384 (comment) ) の 8192bytes配列の限界近辺になりますね

@Hiroshiba
Copy link
Member

おー!調査ありがとうございます!!
プルリクエスト、ぜひ…!!

@anyworks
Copy link
Author

anyworks commented Apr 5, 2022

なるほどです。文字コードの問題でしたか。ありがとうございます&お騒がせしました。
疑問も解消したのでちょっとトライしてみようと思います。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
OS 依存:win Windows に依存した現象
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants