Sample DASD Chargeback Report
from DCOLLECT Type D Records
The sample DCOLLECT report (below) was created with Spectrum DCOLLECT Reporter, Pacific Systems Group's low-cost 4GL DCOLLECT report writer.
One very common use of the DCOLLECT file is to produce a monthly DASD chargeback report (or a showback report). Chargeback reports allow each user of DASD to be internally "charged" for the resources they use. Showback or reportback systems simply report the DASD usage information back to users, so that they can monitor and better use their DASD resources.
In this example, we show one approach to a very simply DASD chargeback report. We use the DCOLLECT D records for this report. There is one type D record for each active dataset.
Step 1. Identify the Dataset's Owner
The first step for each dataset is to decide what internal "customer" to charge for it. Usually that is done by examining the dataset name. (Or, it might be based on the volume serial number that the dataset resides on, or some combination of both. You can examine any field in the D record that helps you determine who to charge for a given dataset.)
In our report, we will assign a "cost center" to be charged for each dataset. (Other companies may want to charge at the department level. They would assign a "department" to charge for each dataset, instead of a "cost center". Use whatever accounting entity works best for your shop.)
In this example, we choose a dataset's cost center based solely on the first node of the dataset name. We use a COMPUTE statement to extract just this first node into an 8-byte character field named MAJOR_NODE.:
COMPUTE: MAJOR_NODE(8) = #LEFT(DCDDSNAM,#INDEX(DCDDSNAM,'.')-1)
We used two built-in functions (#LEFT and #INDEX) to extract all bytes in the dataset name up to the first period. (#INDEX returns the byte number of the first period within DCDDSNAM. Then #LEFT extracts just the bytes before that first period.
Next we use this new MAJOR_NODE field to choose a cost center for the dataset.
COMPUTE: COST_CENTER = WHEN(MAJOR_NODE = 'ACCTGRP') ASSIGN('10010')
WHEN(MAJOR_NODE = 'MANUFAB') ASSIGN('20030')
WHEN(MAJOR_NODE : 'MISC') ASSIGN('20060')
WHEN(MAJOR_NODE = 'SYS1' OR 'ADMIN')
ASSIGN('30100')
ELSE ASSIGN('99999')
There are a couple of things to notice here. We tested for the characters 'MISC' using a colon comparison operator instead of an equals sign. This is a special Spectrum operator that means "contains". So if the MAJOR_NODE field contains the characters "MISC" anywhere within it, the test is passed. This is useful when the text you are looking for might be combined with other text (such as MISC01 and MISC02, for example.)
Also note that we want to assign the same cost center to datasets that begin with either SYS1 or ADMIN. We are able to combine those two tests within a single WHEN parm. (You can also use separate WHEN parms if you prefer.) Remember that a single WHEN parm may include as many tests, on as many different fields from the DCOLLECT record, as you need in order to determine a dataset's owner.
Any dataset that did not match one of our expected values was assigned to cost center 99999. (Someone could then investigate the 99999's in the chargeback report, to come up with additional tests that correctly categorize the unassigned datasets for future runs.)
So the first step, again, is to decide who to charge for a given dataset. Use a single, long conditional COMPUTE statement to do that. In the WHEN parms, you can test any field(s) from the D record that you like. In a real life implementation, there could easily be dozens or hundreds of tests in this COMPUTE statement. For easier and safer maintenance, you might want to put that long COMPUTE statement (along with any related statements, such as the COMPUTE statement for MAJOR_NODE) in a PDS member. Then just use a COPY statement to include that member in your chargeback report job:
COPY: PICKCC /* ASSIGN A VALUE TO COST_CENTER */
The above statement would copy the contents of the member named PICKCC from the PDS identified by the SWCOPY DD in the execution JCL.
Step 2. Determine the Dataset's Cost
Next, we must decide how much to "charge" for the dataset. There are many, many charging schemes used by different shops. The most basic item to charge for is, of course, the amount of space reserved for the dataset. That comes from the "allocated space" field, named DCDALLSP. We could just multiply DCDALLSP by a unit rate to get the cost of the dataset's allocated space. For example, to charge .02 cents per unit of allocated space, we could use:
COMPUTE: ALLOC_COST = DCDALLSP * .0002
However, often a shop will want to charge different unit rates for different cases. Perhaps some departments receive special rates for their DASD usage. Or there may be different rates for different volumes of DASD. There may even be special rates for certain specific datasets. To illustrate how you can assign different rates for different cases, our simple example assigns different rates for certain DASD volumes. There are multiple ways we could do this. We choose to do it by computing an adjustment factor, based on VOLSER, that we will later multiply the basic unit rate by:
COMPUTE: VOLUME_ADJ(NOACCUM) = WHEN(DCDVOLSR = 'VPWRKA') ASSIGN(0.9)
WHEN(DCDVOLSR = 'VPWRKB') ASSIGN(1.2)
ELSE ASSIGN(1.0)
The above COMPUTE statement charges a reduced rate (just 90% of standard rate) for datasets on VPWRKA. But it charges a surcharge (120% of basic rate) for datasets residing on VPWRKB. All other VOLSERs are charged the standard rate (100% of basic rate). (The NOACCUM parm simply tells Spectrum not to total this VOLUME_ADJ field in the total lines.) The use of an adjustment factor makes it very easy to change the rates later. We can simply change one unit rate field, and that change will then be reflected in the adjusted charges for all volumes.
We can now compute the cost of the dataset's allocation by multiplying DCDALLSP by the basic rate, adjusted by the volume adjustment factor:
COMPUTE: ALLOC_RATE = 0.0002
COMPUTE: ALLOC_COST(4) = DCDALLSP * ALLOC_RATE * VOLUME_ADJ
You may notice in our sample chargeback report (below) that our COMPUTE statement also multiplies by an additional adjustment factor, named TARGET_ADJ. We will explain why in a minute ("Step 4. Reconciling Chargebacks to Actual Costs"). For now, just notice that TARGET_ADJ is set to 1.000 early in our code. So, in this example it does not really affect the cost computation at all.
In our example, we also want to charge a separate fee for wasted space. We will define wasted space as any over-allocated space beyond a 15% margin for expected growth. We compute the this wasted DASD by subtracting DCDUSESP (used space) from DCDALLSP (allocated space) and then reducing that amount by 15% of the allocated space. Since this number could go negative (if there is little or no unused space), we will set a floor of zero for this value (using the #MAX built-in function):
COMPUTE: WASTE_ALLOC = #MAX((DCDALLSP - DCDUSESP) - (DCDALLSP * 0.15), 0)
We decide to charge a higher unit rate of .04 cents for wasted space.
COMPUTE: WASTE_RATE = 0.0004
But again, we want to adjust the waste charge based on which VOLSER it resides on. So we compute the WASTE_COST by multiplying the wasted amount by the unit rate for waste and by our volume adjustment factor:
COMPUTE: WASTE_COST(4) = WASTE_ALLOC * WASTE_RATE * VOLUME_ADJ
Finally, our report computes the total cost of the dataset by adding its allocated cost and its waste cost together:
COMPUTE: TOTAL_COST = ALLOC_COST + WASTE_COST
And that is how our chargeback system determines the cost to charge for each dataset.
Step 3. Print Reports Showing the Chargeback Costs
To make the report itself, we use a COLUMNS statement that lists each dataset, its cost center, its total cost, and some of the intermediate calculations. This forms our chargeback detail report. In order to show the total charges for each cost center, we sort the report on the COST_CENTER field and perform a control break on it. The control statements for this report are shown
below. And the report itself is
here.
By adding OPTION: SUMMARY to this report, we can turn this detail report into an executive summary report, which just shows each cost center's total chargeback amount. See here.
Step 4. Reconciling Chargebacks to Actual Costs
If you are able to simply charge some absolute unit rate (like 3 cents, or 1/100 cent, etc.) to owners for allocated and wasted space, then you are done at this point. (You can leave TARGET_ADJ set to 1.000 all the time. Or you can remove that logic from the code altogether.)
But in many shops, it is important that the total costs to be charged back add up to a specific dollar amount each month. (Presumably, the actual amount that the IT department spent to own and maintain all the DASD for that month.) We will call that amount our "target amount."
This is very easy to accomplish. We just need to run our chargeback report twice, taking care each time to properly set two target-related fields:
- the "target adjustment factor" (TARGET_ADJ) that we ran across a little earlier. It should be 1.000 in your first run
- a TARGET_COST field, which we did not discuss, but which you can see near the top of these control statements. You should set this to your desired total charges amount for both runs.
These two fields are used to force the total chargeback amount to match your desired "target" amount. Note that in our initial run in in this figure, we set the TARGET_COST to 200.00 -- the amount that we want all chargeback costs (for this tiny set of records) to add up to. And we set the TARGET_ADJ field to 1.000 for the first of our two runs.
At the end of our sample report's first run, it prints information that we can use to run the report a second time and match the target amount. It prints: the TARGET_COST that was hardcoded in the program ($200), the total of the computed chargeback amounts for this run ($112.88), and the TARGET_ADJ used for this run (1.000):
TARGET_COST: 2,00.00
CHARGEBACK TOTAL: 112.88
CURRENT TARGET_ADJ 1.0000
It then prints out the simple formula that you can use to choose the correct TARGET_ADJ value to use in your second run.
TO MATCH TARGET_COST, CHANGE TARGET_ADJ TO: 1.0000 * 200.00 / 112.88
Performing this calculation (1.0000 * 200 / 112.88), we find that the target factor for our second run should be 1.7718. So we now change one line in the program:
COMPUTE: TARGET_ADJ = 1.7718
Now we run the report a second time using this new TARGET_ADJ value. The total chargeback amount now matches the target cost (possibly with a slight difference due to rounding).
TARGET_COST: 200.00
CHARGEBACK TOTAL: 200.00
CURRENT TARGET_ADJ 1.7718
Conclusion
This is how easy it can be to build a chargeback system using Spectrum DCOLLECT Reporter.
And you can start with this example and customize it as much as you like for your shop.
The powerful 4GL language makes coding even sophisticated systems quick and easy.
Why not download a free Spectrum DCOLLECT Reporter trial right now and start making your own DCOLLECT reports!
INPUT: DCOLLECT /* COPY DCOLLECT RECORD DEFS */
INCLUDEIF: DCURCTYP = 'D' /* SELECT JUST TYPE D RECORDS */
COMPUTE: TARGET_COST = 200.00
COMPUTE: TARGET_ADJ = 1.0000
COMPUTE: MAJOR_NODE(8) = #LEFT(DCDDSNAM,#INDEX(DCDDSNAM,'.')-1)
COMPUTE: COST_CENTER = WHEN(MAJOR_NODE = 'ACCTGRP') ASSIGN('10010')
WHEN(MAJOR_NODE = 'MANUFAB') ASSIGN('20030')
WHEN(MAJOR_NODE : 'MISC') ASSIGN('20060')
WHEN(MAJOR_NODE = 'SYS1' OR 'ADMIN')
ASSIGN('30100')
ELSE ASSIGN('99999')
COMPUTE: VOLUME_ADJ(NOACCUM) = WHEN(DCDVOLSR = 'VPWRKA') ASSIGN(0.9)
WHEN(DCDVOLSR = 'VPWRKB') ASSIGN(1.2)
ELSE ASSIGN(1.0)
COMPUTE: ALLOC_RATE = 0.0002
COMPUTE: ALLOC_COST = DCDALLSP * ALLOC_RATE
* VOLUME_ADJ
* TARGET_ADJ
COMPUTE: WASTE_ALLOC(0) =
#MAX((DCDALLSP - DCDUSESP) - (DCDALLSP * 0.15), 0)
COMPUTE: WASTE_RATE = 0.0004
COMPUTE: WASTE_COST = WASTE_ALLOC * WASTE_RATE
* VOLUME_ADJ
* TARGET_ADJ
COMPUTE: TOTAL_COST = ALLOC_COST + WASTE_COST
COLUMNS: DCDVOLSR('VOLUME')
VOLUME_ADJ(PIC'ZZ9.99')
DCDDSNAM('DATASET|NAME' 30)
COST_CENTER
DCDALLSP('ALLOCATED|SPACE' 12)
DCDUSESP('USED|SPACE' 12)
WASTE_ALLOC('WASTED|SPACE|OVER 15%',12)
ALLOC_COST('CHARGE|FOR|ALLOCATION',PIC'ZZZ,ZZ9.99')
WASTE_COST('CHARGE|FOR|WASTE',PIC'ZZZ,ZZ9.99')
TOTAL_COST(PIC'ZZZ,ZZ9.99')
SORT: COST_CENTER
BREAK: COST_CENTER
BREAK: #GRAND
FOOTING('TARGET_COST:' TARGET_COST(LJ))
FOOTING('CHARGEBACK TOTAL:' TOTAL_COST(TOTAL,LJ, PIC'ZZZ,ZZ9.99'))
FOOTING('CURRENT TARGET_ADJ' TARGET_ADJ(LJ))
FOOTING('TO MATCH TARGET_COST, CHANGE TARGET_ADJ TO:'
TARGET_ADJ(CJ) '*' TARGET_COST(CJ)
'/' TOTAL_COST(TOTAL,PIC'ZZZ,ZZ9.99',CJ))
TITLE: #DATE #TIME / 'DASD CHARGEBACK DETAIL' / 'PAGE' #PAGENUM
TITLE: 'IN COST CENTER ORDER'
08/08/16 4:52 PM DASD CHARGEBACK DETAIL PAGE 1
IN COST CENTER ORDER
UNUSED CHARGE CHARGE
VOLUME DATASET COST ALLOCATED USED SPACE FOR FOR TOTAL
VOLUME ADJ NAME CENTER SPACE SPACE OVER 15% ALLOCATION WASTE COST
VPWRKA 0.90 ACCTGRP.AP304.OBJ 10010 17,431 17,043 0 3.14 0.00 3.14
VPWRKC 1.00 ACCTGRP.AP303.ASM 10010 27,779 15,328 8,284 5.56 3.31 8.87
VPWRKB 1.20 ACCTGRP.AR20104.LOAD 10010 1,107 941 0 0.27 0.00 0.27
VPWRKA 0.90 ACCTGRP.AP400.LST134 10010 9,905 111 8,308 1.78 2.99 4.77
VPWRKB 1.20 ACCTGRP.AP400.LOADLI 10010 29,715 26,008 0 7.13 0.00 7.13
VPWRKA 0.90 ACCTGRP.AP303.OBJ 10010 8,300 4,980 2,075 1.49 0.75 2.24
VPWRKA 0.90 ACCTGRP.AR200.DELOLO 10010 135,573 135,573 0 24.40 0.00 24.40
*** TOTAL FOR 10010 ( 7 ITEMS) 229,810 199,984 18,667 43.77 7.05 50.82
VPWRKC 1.00 MANUFAB.ACME.REPTLIB 20030 5,810 5,036 0 1.16 0.00 1.16
VPWRKD 1.00 MANUFAB.FACTORY2.ZOS 20030 24,901 16,324 4,842 4.98 1.94 6.92
*** TOTAL FOR 20030 ( 2 ITEMS) 30,711 21,360 4,842 6.14 1.94 8.08
VPWRKC 1.00 MISC010.VSAM.EMPLFIL 20060 55 0 47 0.01 0.02 0.03
VPWRKC 1.00 MISC010.SEQ.EMPLFILE 20060 1,273 55 1,027 0.25 0.41 0.67
VPWRKC 1.00 MISC010.VSAM.EMPLFIL 20060 55 0 47 0.01 0.02 0.03
VPWRKB 1.20 MISC010.TEMP190.DATA 20060 277 55 180 0.07 0.09 0.15
*** TOTAL FOR 20060 ( 4 ITEMS) 1,660 110 1,301 0.34 0.53 0.88
VPWRKA 0.90 SYS1.VVDS.VVPWRKA 30100 1,660 0 1,411 0.30 0.51 0.81
VPWRKC 1.00 SYS1.VTOCIX.VPWRKC 30100 775 775 0 0.16 0.00 0.16
VPWRKD 1.00 SYS1.VVDS.VVPWRKD 30100 1,660 0 1,411 0.33 0.56 0.90
VPWRKD 1.00 SYS1.VTOCIX.VPWRKD 30100 775 775 0 0.16 0.00 0.16
VPWRKC 1.00 SYS1.VVDS.VVPWRKC 30100 1,660 0 1,411 0.33 0.56 0.90
VPWRKB 1.20 SYS1.VVDS.VVPWRKB 30100 1,660 0 1,411 0.40 0.68 1.08
VPWRKB 1.20 SYS1.VTOCIX.VPWRKB 30100 775 775 0 0.19 0.00 0.19
VPWRKA 0.90 SYS1.VTOCIX.VPWRKA 30100 775 775 0 0.14 0.00 0.14
*** TOTAL FOR 30100 ( 8 ITEMS) 9,740 3,100 5,644 2.00 2.31 4.31
VPWRKB 1.20 ADMIN01.ITT0906.DATA 99999 23,241 23,186 0 5.58 0.00 5.58
VPWRKC 1.00 ADMIN01.ITT70.ZOSV1R 99999 830 166 540 0.17 0.22 0.38
VPWRKC 1.00 ADMIN01.ITT182.DATA 99999 214,150 213,652 0 42.83 0.00 42.83
*** TOTAL FOR 99999 ( 3 ITEMS) 238,221 237,004 540 48.57 0.22 48.79
TARGET_COST: 200.00
CHARGEBACK TOTAL: 112.88
CURRENT TARGET_ADJ 1.0000
TO MATCH TARGET_COST, CHANGE TARGET_ADJ TO: 1.0000 * 200.00 / 112.88
****** GRAND TOTAL ( 24 ITEMS) 510,142 461,558 30,994 100.83 12.05 112.88
08/08/16 4:52 PM DASD CHARGEBACK SUMMARY PAGE 1
IN COST CENTER ORDER
UNUSED CHARGE CHARGE
VOLUME DATASET COST ALLOCATED USED SPACE FOR FOR TOTAL
VOLUME ADJ NAME CENTER SPACE SPACE OVER 15% ALLOCATION WASTE COST
*** TOTAL FOR 10010 ( 7 ITEMS) 229,810 199,984 18,667 43.77 7.05 50.82
*** TOTAL FOR 20030 ( 2 ITEMS) 30,711 21,360 4,842 6.14 1.94 8.08
*** TOTAL FOR 20060 ( 4 ITEMS) 1,660 110 1,301 0.34 0.53 0.88
*** TOTAL FOR 30100 ( 8 ITEMS) 9,740 3,100 5,644 2.00 2.31 4.31
*** TOTAL FOR 99999 ( 3 ITEMS) 238,221 237,004 540 48.57 0.22 48.79
TARGET_COST: 200.00
CHARGEBACK TOTAL: 112.88
CURRENT TARGET_ADJ 1.0000
TO MATCH TARGET_COST, CHANGE TARGET_ADJ TO: 1.0000 * 200.00 / 112.88
****** GRAND TOTAL ( 24 ITEMS) 510,142 461,558 30,994 100.83 12.05 112.88