如何提高读取大文件的scapy性能

时间:2016-07-26 22:48:30

标签: python performance scapy pcap pypy

我必须读取并解析太大而无法加载到内存中的.pcap文件。我目前正在离线模式下使用嗅探

sniff(offline=file_in, prn=customAction, store=0)

使用大致如下的customAction函数:

customAction(packet):
    global COUNT
    COUNT = COUNT + 1
    # do some other stuff that takes practically 0 time

目前处理数据包的速度太慢。我已经在'驱动程序中使用子进程'程序在不同内核上同时在多个文件上运行此脚本,但我确实需要提高单核性能。

我尝试使用pypy并且对使用pypy的性能比使用python3(anaconda)的性能低10%感到失望。

使用pypy运行50k数据包的平均时间为52.54秒

使用python3运行50k数据包的平均时间是56.93秒

有什么方法可以加快速度吗?

编辑:下面是cProfile的结果,因为你可以看到代码在被分析时有点慢,但所有的时间都花在了做事上。

66054791 function calls (61851423 primitive calls) in 85.482 seconds

Ordered by: cumulative time

ncalls            tottime  percall  cumtime  percall filename:lineno(function)
957/1             0.017    0.000    85.483   85.483  {built-in method builtins.exec}
    1             0.001    0.001    85.483   85.483  parser-3.py:1(<module>)
    1             0.336    0.336    83.039   83.039  sendrecv.py:542(sniff)
50001             0.075    0.000    81.693    0.002  utils.py:817(recv)
50001             0.379    0.000    81.618    0.002  utils.py:794(read_packet)
795097/50003      3.937    0.000    80.140    0.002  base_classes.py:195(__call__)
397549/50003      6.467    0.000    79.543    0.002  packet.py:70(__init__)
397545/50000      1.475    0.000    76.451    0.002  packet.py:616(dissect)
397397/50000      0.817    0.000    74.002    0.001  packet.py:598(do_dissect_payload)
397545/200039     6.908    0.000    49.511    0.000  packet.py:580(do_dissect)
199083            0.806    0.000    32.319    0.000  dns.py:144(getfield)
104043            1.023    0.000    22.996    0.000  dns.py:127(decodeRR)
397548            0.343    0.000    15.059    0.000  packet.py:99(init_fields)
397549            6.043    0.000    14.716    0.000 packet.py:102(do_init_fields)
6673299/6311213   6.832    0.000    13.259    0.000  packet.py:215(__setattr__)
3099782/3095902   5.785    0.000    8.197    0.000  copy.py:137(deepcopy)
3746538/2335718   4.181    0.000    6.980    0.000  packet.py:199(setfieldval)
149866            1.885    0.000    6.678    0.000  packet.py:629(guess_payload_class)
738212            5.730    0.000    6.311    0.000  fields.py:675(getfield)
1756450           3.393    0.000    5.521    0.000  fields.py:78(getfield)
49775             0.200    0.000    5.401    0.000  dns.py:170(decodeRR)
1632614           2.275    0.000    4.591    0.000  packet.py:191(__getattr__)
985050/985037     1.720    0.000    4.229    0.000  {built-in method builtins.hasattr}
326681/194989     0.965    0.000    2.876    0.000  packet.py:122(add_payload)
...

编辑2:完整代码示例:

from scapy.all import *
from scapy.utils import PcapReader
import time, sys, logging


COUNT    = 0
def customAction(packet):
global COUNT
COUNT = COUNT + 1

file_temp = sys.argv[1]
path      = '/'.join(file_temp.split('/')[:-2])
file_in   = '/'.join(file_temp.split('/')[-2:])
name      = file_temp.split('/')[-1:][0].split('.')[0]


os.chdir(path)
q_output_file = 'processed/q_' + name + '.csv'
a_output_file = 'processed/a_' + name + '.csv'
log_file      = 'log/' + name + '.log'

logging.basicConfig(filename=log_file, level=logging.DEBUG)

t0=time.time()
sniff(offline=file_in, prn=customAction, lfilter=lambda x:x.haslayer(DNS), store=0)
t1=time.time()

logging.info("File '{}' took {:.2f} seconds to parse {} packets.".format(name, t1-t0, COUNT))

2 个答案:

答案 0 :(得分:1)

似乎scapy导致PyPy的JIT预热时间很长,但是如果你运行的时间足够久,JIT仍在工作。以下是我得到的结果(在Linux 64上):

size of .pcap        CPython time        PyPy time
2MB                  4.9s                7.3s
5MB                  15.3s               9.1s
15MB                 1m15s               21s

答案 1 :(得分:0)

我认为简短的回答是,Scapy只是慢下来。我尝试用sniff()或PcapReader扫描pcap文件,而不对数据包做任何事情。这个过程从我的SSD读取的速度低于3MB / s,CPU使用率为100%。还有其他用于Python的pcap阅读器库。我建议尝试其中一个。