|
1 | 1 | use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion}; |
2 | | -use iec_61850_lib::decode_smv::{decode_smv, is_smv_frame}; |
| 2 | +use iec_61850_lib::decode_smv::decode_smv; |
| 3 | +use iec_61850_lib::encode_smv::encode_smv; |
| 4 | +use iec_61850_lib::types::{EthernetHeader, Sample, SavAsdu, SavPdu}; |
3 | 5 |
|
4 | 6 | /// Diagnostic function to validate packet structure |
5 | 7 | fn validate_packet(packet: &[u8], name: &str) { |
6 | 8 | println!("\n=== Validating {} ===", name); |
7 | 9 | println!("Packet size: {} bytes", packet.len()); |
8 | 10 |
|
9 | 11 | match decode_smv(packet, 22) { |
10 | | - Ok(num_parsed) => { |
11 | | - println!("✓ Successfully decoded {} bytes", num_parsed); |
12 | | - println!(" Total parsed: {} bytes", num_parsed); |
| 12 | + Ok(pdu) => { |
| 13 | + println!("✓ Successfully decoded PDU"); |
| 14 | + println!(" Number of ASDUs: {}", pdu.no_asdu); |
| 15 | + println!(" Simulation: {}", pdu.sim); |
13 | 16 | } |
14 | 17 | Err(e) => { |
15 | 18 | println!("✗ Decode error at index {}: {}", e.buffer_index, e.message); |
@@ -392,14 +395,6 @@ fn create_sample_smv_packet() -> Vec<u8> { |
392 | 395 | packet |
393 | 396 | } |
394 | 397 |
|
395 | | -fn benchmark_smv_detection(c: &mut Criterion) { |
396 | | - let packet = create_sample_smv_packet(); |
397 | | - |
398 | | - c.bench_function("smv_frame_detection", |b| { |
399 | | - b.iter(|| is_smv_frame(black_box(&packet))); |
400 | | - }); |
401 | | -} |
402 | | - |
403 | 398 | fn benchmark_full_smv_decode(c: &mut Criterion) { |
404 | 399 | let packet = create_sample_smv_packet(); |
405 | 400 |
|
@@ -480,7 +475,7 @@ fn benchmark_max_stress_decode(c: &mut Criterion) { |
480 | 475 | group.finish(); |
481 | 476 | } |
482 | 477 |
|
483 | | -fn benchmark_comparison(c: &mut Criterion) { |
| 478 | +fn benchmark_decode_comparison(c: &mut Criterion) { |
484 | 479 | let small_packet = create_sample_smv_packet(); // 1 ASDU, 8 samples |
485 | 480 | let realistic_packet = create_max_realistic_smv_packet(); // 8 ASDUs, 12 samples each |
486 | 481 | let large_packet = create_max_stress_smv_packet(); // 8 ASDUs, 32 samples each |
@@ -530,12 +525,173 @@ fn benchmark_comparison(c: &mut Criterion) { |
530 | 525 | group.finish(); |
531 | 526 | } |
532 | 527 |
|
| 528 | +/// Helper function to create sample data for encoding benchmarks |
| 529 | +fn create_sample_pdu(num_asdus: usize, samples_per_asdu: usize) -> SavPdu { |
| 530 | + let mut sav_asdu = Vec::new(); |
| 531 | + |
| 532 | + for i in 0..num_asdus { |
| 533 | + let mut samples = Vec::new(); |
| 534 | + for j in 0..samples_per_asdu { |
| 535 | + samples.push(Sample::new( |
| 536 | + 1000 + (i * 100 + j) as i32, |
| 537 | + 0x0000, // good quality |
| 538 | + )); |
| 539 | + } |
| 540 | + |
| 541 | + sav_asdu.push(SavAsdu { |
| 542 | + msv_id: format!("IED1/LLN0$MSVCB{:02}", i + 1), |
| 543 | + dat_set: Some(format!("IED1/LLN0$DATASET{:02}", i + 1)), |
| 544 | + smp_cnt: (i * 1000) as u16, |
| 545 | + conf_rev: 1, |
| 546 | + refr_tm: Some([0x20, 0x21, 0x06, 0x12, 0x0A, 0x30, 0x00, 0x00]), |
| 547 | + smp_synch: 1, |
| 548 | + smp_rate: Some(4000), |
| 549 | + all_data: samples, |
| 550 | + smp_mod: None, |
| 551 | + gm_identity: None, |
| 552 | + }); |
| 553 | + } |
| 554 | + |
| 555 | + SavPdu { |
| 556 | + sim: false, |
| 557 | + no_asdu: num_asdus as u16, |
| 558 | + security: None, |
| 559 | + sav_asdu, |
| 560 | + } |
| 561 | +} |
| 562 | + |
| 563 | +fn benchmark_smv_encode(c: &mut Criterion) { |
| 564 | + let header = EthernetHeader { |
| 565 | + dst_addr: [0x01, 0x0c, 0xcd, 0x04, 0x00, 0x01], |
| 566 | + src_addr: [0x00, 0x11, 0x22, 0x33, 0x44, 0x55], |
| 567 | + tpid: None, |
| 568 | + tci: None, |
| 569 | + ether_type: [0x88, 0xba], // SMV EtherType |
| 570 | + appid: [0x40, 0x00], |
| 571 | + length: [0x00, 0x00], |
| 572 | + }; |
| 573 | + |
| 574 | + let small_pdu = create_sample_pdu(1, 8); // 1 ASDU × 8 samples |
| 575 | + let realistic_pdu = create_sample_pdu(8, 12); // 8 ASDUs × 12 samples |
| 576 | + let stress_pdu = create_sample_pdu(8, 32); // 8 ASDUs × 32 samples |
| 577 | + |
| 578 | + let mut group = c.benchmark_group("smv_encode"); |
| 579 | + |
| 580 | + group.bench_function("small_1x8", |b| { |
| 581 | + b.iter(|| encode_smv(black_box(&header), black_box(&small_pdu))); |
| 582 | + }); |
| 583 | + |
| 584 | + group.bench_function("realistic_8x12", |b| { |
| 585 | + b.iter(|| encode_smv(black_box(&header), black_box(&realistic_pdu))); |
| 586 | + }); |
| 587 | + |
| 588 | + group.bench_function("stress_8x32", |b| { |
| 589 | + b.iter(|| encode_smv(black_box(&header), black_box(&stress_pdu))); |
| 590 | + }); |
| 591 | + |
| 592 | + group.finish(); |
| 593 | +} |
| 594 | + |
| 595 | +fn benchmark_smv_encode_comparison(c: &mut Criterion) { |
| 596 | + let header = EthernetHeader { |
| 597 | + dst_addr: [0x01, 0x0c, 0xcd, 0x04, 0x00, 0x01], |
| 598 | + src_addr: [0x00, 0x11, 0x22, 0x33, 0x44, 0x55], |
| 599 | + tpid: None, |
| 600 | + tci: None, |
| 601 | + ether_type: [0x88, 0xba], |
| 602 | + appid: [0x40, 0x00], |
| 603 | + length: [0x00, 0x00], |
| 604 | + }; |
| 605 | + |
| 606 | + let small_pdu = create_sample_pdu(1, 8); |
| 607 | + let realistic_pdu = create_sample_pdu(8, 12); |
| 608 | + let stress_pdu = create_sample_pdu(8, 32); |
| 609 | + |
| 610 | + println!("\n=== SMV Encoding Performance (Zero-Copy) ==="); |
| 611 | + println!("Testing zero-copy encoding with exact allocation"); |
| 612 | + println!("================================================\n"); |
| 613 | + |
| 614 | + let mut group = c.benchmark_group("smv_encode_comparison"); |
| 615 | + |
| 616 | + // Small packet benchmarks |
| 617 | + group.bench_with_input( |
| 618 | + BenchmarkId::new("zero_copy", "small_1x8"), |
| 619 | + &small_pdu, |
| 620 | + |b, pdu| { |
| 621 | + b.iter(|| encode_smv(black_box(&header), black_box(pdu))); |
| 622 | + }, |
| 623 | + ); |
| 624 | + |
| 625 | + // Realistic packet benchmarks |
| 626 | + group.bench_with_input( |
| 627 | + BenchmarkId::new("zero_copy", "realistic_8x12"), |
| 628 | + &realistic_pdu, |
| 629 | + |b, pdu| { |
| 630 | + b.iter(|| encode_smv(black_box(&header), black_box(pdu))); |
| 631 | + }, |
| 632 | + ); |
| 633 | + |
| 634 | + // Stress packet benchmarks |
| 635 | + group.bench_with_input( |
| 636 | + BenchmarkId::new("zero_copy", "stress_8x32"), |
| 637 | + &stress_pdu, |
| 638 | + |b, pdu| { |
| 639 | + b.iter(|| encode_smv(black_box(&header), black_box(pdu))); |
| 640 | + }, |
| 641 | + ); |
| 642 | + |
| 643 | + group.finish(); |
| 644 | +} |
| 645 | + |
| 646 | +fn benchmark_smv_roundtrip(c: &mut Criterion) { |
| 647 | + let header = EthernetHeader { |
| 648 | + dst_addr: [0x01, 0x0c, 0xcd, 0x04, 0x00, 0x01], |
| 649 | + src_addr: [0x00, 0x11, 0x22, 0x33, 0x44, 0x55], |
| 650 | + tpid: None, |
| 651 | + tci: None, |
| 652 | + ether_type: [0x88, 0xba], |
| 653 | + appid: [0x40, 0x00], |
| 654 | + length: [0x00, 0x00], |
| 655 | + }; |
| 656 | + |
| 657 | + let small_pdu = create_sample_pdu(1, 8); |
| 658 | + let realistic_pdu = create_sample_pdu(8, 12); |
| 659 | + let stress_pdu = create_sample_pdu(8, 32); |
| 660 | + |
| 661 | + let mut group = c.benchmark_group("smv_roundtrip"); |
| 662 | + |
| 663 | + group.bench_function("small_1x8", |b| { |
| 664 | + b.iter(|| { |
| 665 | + let encoded = encode_smv(black_box(&header), black_box(&small_pdu)).unwrap(); |
| 666 | + decode_smv(black_box(&encoded), black_box(22)) |
| 667 | + }); |
| 668 | + }); |
| 669 | + |
| 670 | + group.bench_function("realistic_8x12", |b| { |
| 671 | + b.iter(|| { |
| 672 | + let encoded = encode_smv(black_box(&header), black_box(&realistic_pdu)).unwrap(); |
| 673 | + decode_smv(black_box(&encoded), black_box(22)) |
| 674 | + }); |
| 675 | + }); |
| 676 | + |
| 677 | + group.bench_function("stress_8x32", |b| { |
| 678 | + b.iter(|| { |
| 679 | + let encoded = encode_smv(black_box(&header), black_box(&stress_pdu)).unwrap(); |
| 680 | + decode_smv(black_box(&encoded), black_box(22)) |
| 681 | + }); |
| 682 | + }); |
| 683 | + |
| 684 | + group.finish(); |
| 685 | +} |
| 686 | + |
533 | 687 | criterion_group!( |
534 | 688 | benches, |
535 | | - benchmark_smv_detection, |
536 | 689 | benchmark_full_smv_decode, |
537 | 690 | benchmark_throughput, |
538 | 691 | benchmark_max_stress_decode, |
539 | | - benchmark_comparison |
| 692 | + benchmark_decode_comparison, |
| 693 | + benchmark_smv_encode, |
| 694 | + benchmark_smv_encode_comparison, |
| 695 | + benchmark_smv_roundtrip |
540 | 696 | ); |
541 | 697 | criterion_main!(benches); |
0 commit comments