| 
									
										
										
										
											2018-11-14 12:06:06 -08:00
										 |  |  | #![feature(test)]
 | 
					
						
							|  |  |  | #![cfg(feature = "bpf_c")]
 | 
					
						
							|  |  |  | extern crate test;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-26 07:49:23 -08:00
										 |  |  | use byteorder::{ByteOrder, LittleEndian, WriteBytesExt};
 | 
					
						
							| 
									
										
										
										
											2020-03-31 19:19:59 -07:00
										 |  |  | use solana_rbpf::EbpfVm;
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  | use solana_sdk::{
 | 
					
						
							|  |  |  |     account::Account,
 | 
					
						
							| 
									
										
										
										
											2020-06-13 13:20:08 -07:00
										 |  |  |     entrypoint_native::{InvokeContext, Logger, ProcessInstruction},
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |     instruction::{CompiledInstruction, InstructionError},
 | 
					
						
							|  |  |  |     message::Message,
 | 
					
						
							|  |  |  |     pubkey::Pubkey,
 | 
					
						
							|  |  |  | };
 | 
					
						
							|  |  |  | use std::{cell::RefCell, rc::Rc};
 | 
					
						
							| 
									
										
										
										
											2020-03-26 14:00:26 -07:00
										 |  |  | use std::{env, fs::File, io::Read, mem, path::PathBuf};
 | 
					
						
							| 
									
										
										
										
											2018-11-14 12:06:06 -08:00
										 |  |  | use test::Bencher;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /// BPF program file extension
 | 
					
						
							| 
									
										
										
										
											2018-12-04 22:03:32 -08:00
										 |  |  | const PLATFORM_FILE_EXTENSION_BPF: &str = "so";
 | 
					
						
							| 
									
										
										
										
											2018-11-14 12:06:06 -08:00
										 |  |  | /// Create a BPF program file name
 | 
					
						
							|  |  |  | fn create_bpf_path(name: &str) -> PathBuf {
 | 
					
						
							|  |  |  |     let mut pathbuf = {
 | 
					
						
							|  |  |  |         let current_exe = env::current_exe().unwrap();
 | 
					
						
							|  |  |  |         PathBuf::from(current_exe.parent().unwrap().parent().unwrap())
 | 
					
						
							|  |  |  |     };
 | 
					
						
							|  |  |  |     pathbuf.push("bpf/");
 | 
					
						
							|  |  |  |     pathbuf.push(name);
 | 
					
						
							|  |  |  |     pathbuf.set_extension(PLATFORM_FILE_EXTENSION_BPF);
 | 
					
						
							|  |  |  |     pathbuf
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-26 14:00:26 -07:00
										 |  |  | fn empty_check(_prog: &[u8]) -> Result<(), solana_bpf_loader_program::BPFError> {
 | 
					
						
							| 
									
										
										
										
											2018-11-14 12:06:06 -08:00
										 |  |  |     Ok(())
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-04 09:56:27 -08:00
										 |  |  | fn load_elf() -> Result<Vec<u8>, std::io::Error> {
 | 
					
						
							|  |  |  |     let path = create_bpf_path("bench_alu");
 | 
					
						
							|  |  |  |     let mut file = File::open(&path).expect(&format!("Unable to open {:?}", path));
 | 
					
						
							|  |  |  |     let mut elf = Vec::new();
 | 
					
						
							|  |  |  |     file.read_to_end(&mut elf).unwrap();
 | 
					
						
							|  |  |  |     Ok(elf)
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-14 12:06:06 -08:00
										 |  |  | const ARMSTRONG_LIMIT: u64 = 500;
 | 
					
						
							|  |  |  | const ARMSTRONG_EXPECTED: u64 = 5;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #[bench]
 | 
					
						
							|  |  |  | fn bench_program_load_elf(bencher: &mut Bencher) {
 | 
					
						
							| 
									
										
										
										
											2019-03-04 09:56:27 -08:00
										 |  |  |     let elf = load_elf().unwrap();
 | 
					
						
							| 
									
										
										
										
											2020-03-26 14:00:26 -07:00
										 |  |  |     let mut vm = EbpfVm::<solana_bpf_loader_program::BPFError>::new(None).unwrap();
 | 
					
						
							| 
									
										
										
										
											2018-11-14 12:06:06 -08:00
										 |  |  |     vm.set_verifier(empty_check).unwrap();
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     bencher.iter(|| {
 | 
					
						
							|  |  |  |         vm.set_elf(&elf).unwrap();
 | 
					
						
							|  |  |  |     });
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #[bench]
 | 
					
						
							|  |  |  | fn bench_program_verify(bencher: &mut Bencher) {
 | 
					
						
							| 
									
										
										
										
											2019-03-04 09:56:27 -08:00
										 |  |  |     let elf = load_elf().unwrap();
 | 
					
						
							| 
									
										
										
										
											2020-03-26 14:00:26 -07:00
										 |  |  |     let mut vm = EbpfVm::<solana_bpf_loader_program::BPFError>::new(None).unwrap();
 | 
					
						
							| 
									
										
										
										
											2018-11-14 12:06:06 -08:00
										 |  |  |     vm.set_verifier(empty_check).unwrap();
 | 
					
						
							|  |  |  |     vm.set_elf(&elf).unwrap();
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     bencher.iter(|| {
 | 
					
						
							| 
									
										
										
										
											2019-11-20 16:32:19 -08:00
										 |  |  |         vm.set_verifier(solana_bpf_loader_program::bpf_verifier::check)
 | 
					
						
							| 
									
										
										
										
											2018-11-14 12:06:06 -08:00
										 |  |  |             .unwrap();
 | 
					
						
							|  |  |  |     });
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #[bench]
 | 
					
						
							|  |  |  | fn bench_program_alu(bencher: &mut Bencher) {
 | 
					
						
							|  |  |  |     let ns_per_s = 1000000000;
 | 
					
						
							|  |  |  |     let one_million = 1000000;
 | 
					
						
							|  |  |  |     let mut inner_iter = vec![];
 | 
					
						
							|  |  |  |     inner_iter
 | 
					
						
							|  |  |  |         .write_u64::<LittleEndian>(ARMSTRONG_LIMIT)
 | 
					
						
							|  |  |  |         .unwrap();
 | 
					
						
							| 
									
										
										
										
											2018-11-26 07:49:23 -08:00
										 |  |  |     inner_iter.write_u64::<LittleEndian>(0).unwrap();
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |     let mut invoke_context = MockInvokeContext::default();
 | 
					
						
							| 
									
										
										
										
											2018-11-14 12:06:06 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-04 09:56:27 -08:00
										 |  |  |     let elf = load_elf().unwrap();
 | 
					
						
							| 
									
										
										
										
											2020-05-26 01:02:31 -07:00
										 |  |  |     let (mut vm, _) = solana_bpf_loader_program::create_vm(&elf, &[], &mut invoke_context).unwrap();
 | 
					
						
							| 
									
										
										
										
											2018-11-14 12:06:06 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     println!("Interpreted:");
 | 
					
						
							|  |  |  |     assert_eq!(
 | 
					
						
							| 
									
										
										
										
											2019-09-06 16:05:01 -07:00
										 |  |  |         0, /*success*/
 | 
					
						
							| 
									
										
										
										
											2019-05-24 16:21:42 -07:00
										 |  |  |         vm.execute_program(&mut inner_iter, &[], &[]).unwrap()
 | 
					
						
							| 
									
										
										
										
											2018-11-14 12:06:06 -08:00
										 |  |  |     );
 | 
					
						
							| 
									
										
										
										
											2018-11-26 07:49:23 -08:00
										 |  |  |     assert_eq!(ARMSTRONG_LIMIT, LittleEndian::read_u64(&inner_iter));
 | 
					
						
							|  |  |  |     assert_eq!(
 | 
					
						
							|  |  |  |         ARMSTRONG_EXPECTED,
 | 
					
						
							|  |  |  |         LittleEndian::read_u64(&inner_iter[mem::size_of::<u64>()..])
 | 
					
						
							|  |  |  |     );
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-14 12:06:06 -08:00
										 |  |  |     bencher.iter(|| {
 | 
					
						
							| 
									
										
										
										
											2019-05-24 16:21:42 -07:00
										 |  |  |         vm.execute_program(&mut inner_iter, &[], &[]).unwrap();
 | 
					
						
							| 
									
										
										
										
											2018-11-14 12:06:06 -08:00
										 |  |  |     });
 | 
					
						
							|  |  |  |     let instructions = vm.get_last_instruction_count();
 | 
					
						
							|  |  |  |     let summary = bencher.bench(|_bencher| {}).unwrap();
 | 
					
						
							|  |  |  |     println!("  {:?} instructions", instructions);
 | 
					
						
							|  |  |  |     println!("  {:?} ns/iter median", summary.median as u64);
 | 
					
						
							|  |  |  |     assert!(0f64 != summary.median);
 | 
					
						
							|  |  |  |     let mips = (instructions * (ns_per_s / summary.median as u64)) / one_million;
 | 
					
						
							|  |  |  |     println!("  {:?} MIPS", mips);
 | 
					
						
							| 
									
										
										
										
											2018-11-21 12:16:16 -08:00
										 |  |  |     println!("{{ \"type\": \"bench\", \"name\": \"bench_program_alu_interpreted_mips\", \"median\": {:?}, \"deviation\": 0 }}", mips);
 | 
					
						
							| 
									
										
										
										
											2018-11-14 12:06:06 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-23 11:03:53 -07:00
										 |  |  |     // JIT disabled until address translation support is added
 | 
					
						
							|  |  |  |     // println!("JIT to native:");
 | 
					
						
							|  |  |  |     // vm.jit_compile().unwrap();
 | 
					
						
							|  |  |  |     // unsafe {
 | 
					
						
							|  |  |  |     //     assert_eq!(
 | 
					
						
							| 
									
										
										
										
											2019-09-06 16:05:01 -07:00
										 |  |  |     //         0, /*success*/
 | 
					
						
							| 
									
										
										
										
											2019-08-23 11:03:53 -07:00
										 |  |  |     //         vm.execute_program_jit(&mut inner_iter).unwrap()
 | 
					
						
							|  |  |  |     //     );
 | 
					
						
							|  |  |  |     // }
 | 
					
						
							|  |  |  |     // assert_eq!(ARMSTRONG_LIMIT, LittleEndian::read_u64(&inner_iter));
 | 
					
						
							|  |  |  |     // assert_eq!(
 | 
					
						
							|  |  |  |     //     ARMSTRONG_EXPECTED,
 | 
					
						
							|  |  |  |     //     LittleEndian::read_u64(&inner_iter[mem::size_of::<u64>()..])
 | 
					
						
							|  |  |  |     // );
 | 
					
						
							| 
									
										
										
										
											2018-11-26 07:49:23 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-23 11:03:53 -07:00
										 |  |  |     // bencher.iter(|| unsafe {
 | 
					
						
							|  |  |  |     //     vm.execute_program_jit(&mut inner_iter).unwrap();
 | 
					
						
							|  |  |  |     // });
 | 
					
						
							|  |  |  |     // let summary = bencher.bench(|_bencher| {}).unwrap();
 | 
					
						
							|  |  |  |     // println!("  {:?} instructions", instructions);
 | 
					
						
							|  |  |  |     // println!("  {:?} ns/iter median", summary.median as u64);
 | 
					
						
							|  |  |  |     // assert!(0f64 != summary.median);
 | 
					
						
							|  |  |  |     // let mips = (instructions * (ns_per_s / summary.median as u64)) / one_million;
 | 
					
						
							|  |  |  |     // println!("  {:?} MIPS", mips);
 | 
					
						
							|  |  |  |     // println!("{{ \"type\": \"bench\", \"name\": \"bench_program_alu_jit_to_native_mips\", \"median\": {:?}, \"deviation\": 0 }}", mips);
 | 
					
						
							| 
									
										
										
										
											2018-11-14 12:06:06 -08:00
										 |  |  | }
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | #[derive(Debug, Default)]
 | 
					
						
							| 
									
										
										
										
											2020-05-08 16:05:54 -07:00
										 |  |  | pub struct MockInvokeContext {
 | 
					
						
							|  |  |  |     key: Pubkey,
 | 
					
						
							| 
									
										
										
										
											2020-06-13 13:20:08 -07:00
										 |  |  |     mock_logger: MockLogger,
 | 
					
						
							| 
									
										
										
										
											2020-05-08 16:05:54 -07:00
										 |  |  | }
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  | impl InvokeContext for MockInvokeContext {
 | 
					
						
							|  |  |  |     fn push(&mut self, _key: &Pubkey) -> Result<(), InstructionError> {
 | 
					
						
							|  |  |  |         Ok(())
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  |     fn pop(&mut self) {}
 | 
					
						
							|  |  |  |     fn verify_and_update(
 | 
					
						
							|  |  |  |         &mut self,
 | 
					
						
							|  |  |  |         _message: &Message,
 | 
					
						
							|  |  |  |         _instruction: &CompiledInstruction,
 | 
					
						
							|  |  |  |         _accounts: &[Rc<RefCell<Account>>],
 | 
					
						
							|  |  |  |     ) -> Result<(), InstructionError> {
 | 
					
						
							|  |  |  |         Ok(())
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2020-05-08 16:05:54 -07:00
										 |  |  |     fn get_caller(&self) -> Result<&Pubkey, InstructionError> {
 | 
					
						
							|  |  |  |         Ok(&self.key)
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2020-06-03 12:48:19 -07:00
										 |  |  |     fn get_programs(&self) -> &[(Pubkey, ProcessInstruction)] {
 | 
					
						
							|  |  |  |         &[]
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2020-06-13 13:20:08 -07:00
										 |  |  |     fn get_logger(&self) -> Rc<RefCell<dyn Logger>> {
 | 
					
						
							|  |  |  |         Rc::new(RefCell::new(self.mock_logger.clone()))
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | #[derive(Debug, Default, Clone)]
 | 
					
						
							|  |  |  | pub struct MockLogger {
 | 
					
						
							|  |  |  |     pub log: Rc<RefCell<Vec<String>>>,
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | impl Logger for MockLogger {
 | 
					
						
							| 
									
										
										
										
											2020-06-06 10:18:28 -07:00
										 |  |  |     fn log_enabled(&self) -> bool {
 | 
					
						
							| 
									
										
										
										
											2020-06-13 13:20:08 -07:00
										 |  |  |         true
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  |     fn log(&mut self, message: &str) {
 | 
					
						
							|  |  |  |         self.log.borrow_mut().push(message.to_string());
 | 
					
						
							| 
									
										
										
										
											2020-06-06 10:18:28 -07:00
										 |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  | }
 |