• OPNET学习笔记之simple_source模块


    simple_source模块的功能是按照配置产生包,包括不同的包格式和产生速率,也是比较简单的进程模型。

    参考了《opnet process model:simple_source分析http://hi.baidu.com/ebinghaus/blog/item/c7cade9228876c83a877a405.html

      该模块有4个local statistic,注意有5个model attribute,分别是Packet Interarrival Time,Packet Size,Packet Format,Start Time,Stop Time,这些是在使用该模块时需要配置的,当然也可以使用默认配置。

    状态机也很简单:

    在header block中定义了

    /* Include files.     */
    #include <oms_dist_support.h>  //注意该模块使用了外部文件《oms_dist_support》和《oms_string_support》

    /* Special attribute values.  */
    #define  SSC_INFINITE_TIME  -1.0    //定义无穷大时间为-1

    /* Interrupt code values.   */  //注意这里的中断代码是自定义的,为了在产生自中断是使用
    #define  SSC_START    0
    #define  SSC_GENERATE   1
    #define  SSC_STOP    2

    /* Node configuration constants. */
    #define  SSC_STRM_TO_LOW   0    //发送的stream index,默认的,该模块只有一个stream连接,所以不需要动态获取stream index

    /* Macro definitions for state  transitions.*/   //转换条件为中断代码是自定义的常量:

    #define  START    (intrpt_code == SSC_START)
    #define  DISABLED   (intrpt_code == SSC_STOP)
    #define  STOP    (intrpt_code == SSC_STOP)
    #define  PACKET_GENERATE  (intrpt_code == SSC_GENERATE)

    /* Function prototypes.    */
    static void   ss_packet_generate (void);  //产生包的函数,在function block中定义

    一,INIT的入口代码:

    /* At this initial state, we read the values of source attributes */
    /* and schedule a selt interrupt that will indicate our start time */
    /* for packet generation.           */

    /* Obtain the object id of the surrounding module.     */
    own_id = op_id_self ();        //首先得到surrounding objid,应该是自己的objid,后面根据objid获取对象的属性

    /* Read the values of the packet generation parameters, i.e. the */
    /* attribute values of the surrounding module.      */

    //用op_ima_obj_attr_get()得到对象的属性的值,是产生包的参数。注意interarrival_str和size_str是临时变量,还是char数组类型。
    op_ima_obj_attr_get (own_id, "Packet Interarrival Time", interarrival_str);
    op_ima_obj_attr_get (own_id, "Packet Size",              size_str);
    op_ima_obj_attr_get (own_id, "Packet Format",            format_str);
    op_ima_obj_attr_get (own_id, "Start Time",               &start_time);
    op_ima_obj_attr_get (own_id, "Stop Time",                &stop_time);

    /* Load the PDFs that will be used in computing the packet   */
    /* interarrival times and packet sizes.        */

    //装入PDF,用于前两个参数,得到包产生和包大小的分布,函数是oms_dist_load_from_string(),这样很方便的使用string类型的参数。
    //获得的是分布函数的句柄,注意两个句柄都是state variable,类型为Omst_dist_handle。

    interarrival_dist_ptr = oms_dist_load_from_string (interarrival_str);
    pksize_dist_ptr       = oms_dist_load_from_string (size_str);

    /* Verify the existence of the packet format to be used for   generated packets. */
    if (strcmp (format_str, "NONE") == 0)  //检查是否是无格式包
     {
     /* We will generate unformatted packets. Set the flag.   */
     generate_unformatted = OPC_TRUE;
     }
    else
     {
     /* We will generate formatted packets. Turn off the flag.  */
     generate_unformatted = OPC_FALSE;  //不是无格式包

     /* Get the list of all available packet formats.    */

    //用prg_tfile_name_list_get()得到所有可用的包格式
     pk_format_names_lptr = prg_tfile_name_list_get (PrgC_Tfile_Type_Packet_Format);

     /* Search the list for the requested packet format.    */
     format_found = OPC_FALSE;
     for (i = prg_list_size (pk_format_names_lptr); ((format_found == OPC_FALSE) && (i > 0)); i--)
      {
      /* Access the next format name and compare with requested format name */
      found_format_str = (char *) prg_list_access (pk_format_names_lptr, i - 1);
      if (strcmp (found_format_str, format_str) == 0)
       format_found = OPC_TRUE;  //找到了需求的包格式
      }

        if (format_found == OPC_FALSE)
      {
      /* The requested format does not exist. Generate unformatted packets.     */
      generate_unformatted = OPC_TRUE;
     
      /* Display an appropriate warning.       */
      op_prg_odb_print_major ("Warning from simple packet generator model (simple_source):",
            "The specified packet format", format_str,
            "is not found. Generating unformatted packets instead.", OPC_NIL);
      }

     /* Destroy the lits and its elements since we don't need it  */
     /* anymore.              */
     prg_list_free (pk_format_names_lptr);
     prg_mem_free  (pk_format_names_lptr);
     } 
     
    /* Make sure we have valid start and stop times, i.e. stop time is  not earlier than start time. */
    if ((stop_time <= start_time) && (stop_time != SSC_INFINITE_TIME))  //开始/结束时间不合法,设置开始仿真时间为无穷大
     {
     /* Stop time is earlier than start time. Disable the source. */
     start_time = SSC_INFINITE_TIME;

     /* Display an appropriate warning.        */
     op_prg_odb_print_major ("Warning from simple packet generator model (simple_source):",
           "Although the generator is not disabled (start time is set to a finite value),",
           "a stop time that is not later than the start time is specified.",
           "Disabling the generator.", OPC_NIL);
     }

    /* Schedule a self interrupt that will indicate our start time for */
    /* packet generation activities. If the source is disabled,   */
    /* schedule it at current time with the appropriate code value.  */

    //产生自中断,以指示开始产生包的时间,如果停止产生包时刻小于开始产生包的时刻(这时开始产生包的时间是无限大)在当前仿真时刻产生中断号为SSC_STOP中断
    if (start_time == SSC_INFINITE_TIME)
     {
     op_intrpt_schedule_self (op_sim_time (), SSC_STOP);  //马上给出自中断
     }
    else
     {
     op_intrpt_schedule_self (start_time, SSC_START);   //自中断,在开始时间,中断号为SSC_START

     /* In this case, also schedule the interrupt when we will stop */
     /* generating packets, unless we are configured to run until */
     /* the end of the simulation.         */
     if (stop_time != SSC_INFINITE_TIME)
      {
      op_intrpt_schedule_self (stop_time, SSC_STOP);  //当结束时间不是无限大时,在结束时间产生自中断,中断号为SSC_STOP
      }
     
     next_intarr_time = oms_dist_outcome (interarrival_dist_ptr);  //通过分布函数句柄计算产生下一个包的时间间隔,这里是state variable

     /* Make sure that interarrival time is not negative. In that case it will be set to 0.*/
     if (next_intarr_time <0)
      {
      next_intarr_time = 0.0;  //保证间隔时间不小于0
      }

     }

    /* Register the statistics that will be maintained by this model. */

    //注册局部统计量,返回局部统计量的句柄
    bits_sent_hndl      = op_stat_reg ("Generator.Traffic Sent (bits/sec)",   OPC_STAT_INDEX_NONE, OPC_STAT_LOCAL);
    packets_sent_hndl   = op_stat_reg ("Generator.Traffic Sent (packets/sec)",  OPC_STAT_INDEX_NONE, OPC_STAT_LOCAL);
    packet_size_hndl    = op_stat_reg ("Generator.Packet Size (bits)",              OPC_STAT_INDEX_NONE, OPC_STAT_LOCAL);
    interarrivals_hndl  = op_stat_reg ("Generator.Packet Interarrival Time (secs)", OPC_STAT_INDEX_NONE, OPC_STAT_LOCAL);

    二,由于初始状态是非强制状态,进程执行完入口代码后,停留在该状态等待中断触发转移状态,仿真时刻到10s(属性start_time设置的值)时将产生中断号为SSC_START中断,中断产生后将首先执行当前状态的出口代码,初始状态的出口代码如下:
    intrpt_code = op_intrpt_code ();  //得到当前的中断代码

    这时条件START满足,进程将从初始状态转换到generate状态,转移时首先执行转移函数ss_packet_generate (void),在function block中定义的转移函数如下:

    static void ss_packet_generate (void)
     {
     Packet*    pkptr;
     double    pksize;

     /** This function creates a packet based on the packet generation  **/
     /** specifications of the source model and sends it to the lower layer. **/
     FIN (ss_packet_generate ());

     /* Generate a packet size outcome.     */
     pksize = (double) ceil (oms_dist_outcome (pksize_dist_ptr));  //通过分布函数句柄得到包大小,再通过ceil()函数向上舍入,得到包大小
     
     /* Create a packet of specified format and size. */
     if (generate_unformatted == OPC_TRUE)
      {
      /* We produce unformatted packets. Create one. */
      pkptr = op_pk_create (pksize);            //使用op_pk_creat()函数产生无格式包
      }
     else
      {
      /* Create a packet with the specified format. */
      pkptr = op_pk_create_fmt (format_str);      //使用op_pk_creat_fmt()函数产生有格式包
      op_pk_total_size_set (pkptr, pksize);        //置有格式包的总大小
      }

     /* Update the packet generation statistics.   */  //通过局部统计量句柄更新统计量,注意xxx/sec的量都是在更新后马上清零
     op_stat_write (packets_sent_hndl, 1.0);
     op_stat_write (packets_sent_hndl, 0.0);
     op_stat_write (bits_sent_hndl, (double) pksize);
     op_stat_write (bits_sent_hndl, 0.0);
     op_stat_write (packet_size_hndl, (double) pksize);
     op_stat_write (interarrivals_hndl, next_intarr_time);

     /* Send the packet via the stream to the lower layer. */
     op_pk_send (pkptr, SSC_STRM_TO_LOW);    //发送包到定义好的stream index,默认为0

     FOUT;
     } 

    三, 执行完转移函数后将跳到generate状态,并首先执行入口代码,如下:

    /* At the enter execs of the "generate" state we schedule the  */
    /* arrival of the next packet.          */
    next_intarr_time = oms_dist_outcome (interarrival_dist_ptr);  //通过分布函数句柄得到下一个包的产生时间间隔

    /* Make sure that interarrival time is not negative. In that case it will be set to 0.*/
    if (next_intarr_time <0)
     {
     next_intarr_time = 0;
     }

    //在当前时间+间隔时间后,产生自中断,中断号为SSC_GENERATE,注意返回值为Evhandle类型

    next_pk_evh = op_intrpt_schedule_self (op_sim_time () + next_intarr_time, SSC_GENERATE);

    四,执行完入口代码后,进程将停留在generate状态等待中断,当下一个中断发生,进行状态转换,首先执行generate状态的出口代码:

    intrpt_code = op_intrpt_code ();  //得到中断号

    然后判断转移条件。

    如果是STOP,执行stop状态的入口代码:

    /* When we enter into the "stop" state, it is the time for us to */
    /* stop generating traffic. We simply cancel the generation of the */
    /* next packet and go into a silent mode by not scheduling anything */
    /* else.               */
    if (op_ev_valid (next_pk_evh) == OPC_TRUE)    //如果下一个事件仍然有效,就取消该事件,使用事件句柄
     {
     op_ev_cancel (next_pk_evh);
     }

  • 相关阅读:
    Java基础--JDBC
    DQL---连接查询(内连接、外连接)、子查询、分页查询
    Java基础--注解、反射
    1、Centos7系统安装docker,并配置阿里云镜像加速器
    linux——vim命令
    linux——yum命令
    linux——ps命令
    31、springboot——缓存之JSR107——@Caching和@CacheConfig的使用⑤
    30、springboot——缓存之JSR107——@CacheEvict的使用④
    30、springboot——缓存之JSR107——@CachePut的使用③
  • 原文地址:https://www.cnblogs.com/loopever/p/2599902.html
Copyright © 2020-2023  润新知