2016-11-18 8 views
5

のスイッチIは、センサ情報を収集するためにシリアルデバイスとインターフェース2つのアッカScalaのアプリケーションを維持し、開発しています。 2つの主な違いは、1つのCPU(My CO2センサーアプリケーション)が1%のCPUを使用し、もう1つ(マイパワーセンサーアプリケーション)が250%のCPUを使用することです。これはLinuxマシン(Raspberry Pi 3)と私のWindowsデスクトップPCの両方のケースです。コード上、主な相違点は、CO2がシリアルライブラリ(http://fazecast.github.io/jSerialComm/)を直接使用しているのに対し、PowerセンサーアプリケーションはシリアルライブラリのIn/OutputStreamをAkkaソース/シンクに変換するためのミドルウェア層を通過するということです。高いCPU使用率がアッカアプリケーション

- この情報を使用して https://stackoverflow.com/a/29414580/1122834:私は次のように答えを見つけることが Profiler screenshot

Unsafe.parkのためにグーグルで後:私は、私はすぐにそれに反対プロファイラ(VisualVMの)平手打ちこの高いCPU使用率を見たとき

val port = SerialPort.getCommPort(comPort) 

    port.setBaudRate(baudRate) 
    port.setFlowControl(flowControl) 
    port.setComPortParameters(baudRate, dataBits, stopBits, parity) 
    port.setComPortTimeouts(timeoutMode, timeout, timeout) 

    val isOpen = port.openPort() 

    if(!isOpen) { 
    error(s"Port $comPort could not opened. Use the following documentation for troubleshooting: https://github.com/Fazecast/jSerialComm/wiki/Troubleshooting") 

    throw new Exception("Port could not be opened") 
    } 

    (reactive.streamSource(port.getInputStream), reactive.streamSink(port.getOutputStream)) 

は、以下の私に言いましたパワーセンサーアプリの有無にかかわらずコンテキスト切り替えの量を確認したところ、結果は非常に明確でした問題の根本的な原因:あなたが見ることができるように

[email protected]:~ $ vmstat 1 
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu----- 
r b swpd free buff cache si so bi bo in cs us sy id wa st 
10 0 32692 80144 71228 264356 0 0  0  5 7 8 38 5 55 2 0 
1 0 32692 80176 71228 264356 0 0  0 76 12932 18856 59 6 35 0 0 
1 0 32692 80208 71228 264356 0 0  0  0 14111 20570 60 8 32 0 0 
1 0 32692 80208 71228 264356 0 0  0  0 13186 16095 65 6 29 0 0 
1 0 32692 80176 71228 264356 0 0  0  0 14008 23449 56 6 38 0 0 
3 0 32692 80208 71228 264356 0 0  0  0 13528 17783 65 6 29 0 0 
1 0 32692 80208 71228 264356 0 0  0 28 12960 16588 63 6 31 0 0 

[email protected]:~ $ vmstat 1 
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu----- 
r b swpd free buff cache si so bi bo in cs us sy id wa st 
1 0 32692 147320 71228 264332 0 0  0  5 7 8 38 5 55 2 0 
0 0 32692 147296 71228 264332 0 0  0 84 963 1366 0 0 98 2 0 
0 0 32692 147296 71228 264332 0 0  0  0 962 1347 1 0 99 0 0 
0 0 32692 147296 71228 264332 0 0  0  0 947 1318 1 0 99 0 0 

は、コンテキストスイッチの量はちょうど私のアプリケーションを殺すことによって〜12000秒でダウンしました。私は、正確なスレッドがこれをやっていたそのチェックによって続け、そしてアッカがものを行うことは本当に熱望しているようだ: Profiler threads

ここでコメントし、アッカの並列処理の設定を微調整に向けた別のSO質問ポイントの両方。私は次のものを私のapplication.confに追加しました。結果はありません。

akka { 
    log-config-on-start = "on" 
    actor{ 
    default-dispatcher { 
     # Dispatcher is the name of the event-based dispatcher 
     type = Dispatcher 
     # What kind of ExecutionService to use 
     executor = "fork-join-executor" 
     # Configuration for the fork join pool 
     default-executor { 
     fallback = "fork-join-executor" 
     } 
     fork-join-executor { 
     # Min number of threads to cap factor-based parallelism number to 
     parallelism-min = 1 
     # Parallelism (threads) ... ceil(available processors * factor) 
     parallelism-factor = 1.0 
     # Max number of threads to cap factor-based parallelism number to 
     parallelism-max = 1 
     } 
     # Throughput defines the maximum number of messages to be 
     # processed per actor before the thread jumps to the next actor. 
     # Set to 1 for as fair as possible. 
     throughput = 1 
    } 
    } 
    stream{ 
    default-blocking-io-dispatcher { 
     type = PinnedDispatcher 
     executor = "fork-join-executor" 
     throughput = 1 

     thread-pool-executor { 
     core-pool-size-min = 1 
     core-pool-size-factor = 1.0 
     core-pool-size-max = 1 
     } 
     fork-join-executor { 
     parallelism-min = 1 
     parallelism-factor = 1.0 
     parallelism-max = 1 
     } 
    } 
    } 
} 

これはCPU使用率(100% - > 65%)を向上させるようですが、CPU使用率が不必要に高くなります。

UPDATE 21-11 -'16 グラフ内に問題があるようです。グラフを実行していないときは、CPU使用率はすぐに通常のレベルに低下します。グラフは次のとおりです。

val streamGraph = RunnableGraph.fromGraph(GraphDSL.create() { implicit builder => 
    import GraphDSL.Implicits._ 

    val responsePacketSource = serialSource 
    .via(Framing.delimiter(ByteString(frameDelimiter), maxFrameLength, allowTruncation = true)) 
    .via(cleanPacket) 
    .via(printOutput("Received: ",debug(_))) 
    .via(byteStringToResponse) 

    val packetSink = pushSource 
    .via(throttle(throttle)) 

    val zipRequestStickResponse = builder.add(Zip[RequestPacket, ResponsePacket]) 
    val broadcastRequest = builder.add(Broadcast[RequestPacket](2)) 
    val broadcastResponse = builder.add(Broadcast[ResponsePacket](2)) 

    packetSink ~> broadcastRequest.in 
    broadcastRequest.out(0) ~> makePacket ~> printOutput("Sent: ",debug(_)) ~> serialSink 
    broadcastRequest.out(1) ~> zipRequestStickResponse.in0 

    responsePacketSource ~> broadcastResponse.in 
    broadcastResponse.out(0).filter(isStickAck) ~> zipRequestStickResponse.in1 
    broadcastResponse.out(1).filter(!isStickAck(_)).map (al => { 
    val e = completeRequest(al) 
    debug(s"Sinking:   $e") 
    e 
    }) ~> Sink.ignore 

    zipRequestStickResponse.out.map { case(request, stickResponse) => 
    debug(s"Mapping: request=$request, stickResponse=$stickResponse") 
    pendingPackets += stickResponse.sequenceNumber -> request 
    request.stickResponse trySuccess stickResponse 
    } ~> Sink.ignore 

    ClosedShape 
}) 

streamGraph.run() 

broadcastResponseからフィルタを削除すると、CPU使用率が通常のレベルに低下します。これは、ジップが起こらないと信じるようになります。したがって、グラフは不正な状態になります。

+0

デフォルトディスパッチャとblocking-ioディスパッチャの並列数を減らしてください。ワークロードが通常CPUにバインドされていない場合は、thread-pool-executorに切り替えることを検討してください。 –

+0

@ViktorKlangディスパッチャを調整する際に私が試みたことを反映するために私の質問を編集しました – Lolmewn

+0

デフォルトのblocking-io-dispatcherを再設定していません –

答えて

3

FazecastのjSerialCommライブラリには、さまざまなタイムアウトモードがあります。アッカストリームのInputStreamPublisherと組み合わせた場合、非ブロッキングread()方法(TIMEOUT_NONBLOCKING)を使用

static final public int TIMEOUT_NONBLOCKING = 0x00000000; 
static final public int TIMEOUT_READ_SEMI_BLOCKING = 0x00000001; 
static final public int TIMEOUT_WRITE_SEMI_BLOCKING = 0x00000010; 
static final public int TIMEOUT_READ_BLOCKING = 0x00000100; 
static final public int TIMEOUT_WRITE_BLOCKING = 0x00001000; 
static final public int TIMEOUT_SCANNER = 0x00010000; 

は、非常に高いCPU使用率になります。これを防ぐには、単にTIMEOUT_READ_SEMI_BLOCKINGまたはTIMEOUT_READ_BLOCKINGを使用してください。